blob: c37371fc9e01a4c818f2402606d9aa9739c764a7 [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>
Michael Bueschd1ca6c42006-03-25 15:43:18 +010041#include <linux/dma-mapping.h>
John W. Linvillef2223132006-01-23 16:59:58 -050042#include <net/iw_handler.h>
43
44#include "bcm43xx.h"
45#include "bcm43xx_main.h"
46#include "bcm43xx_debugfs.h"
47#include "bcm43xx_radio.h"
48#include "bcm43xx_phy.h"
49#include "bcm43xx_dma.h"
50#include "bcm43xx_pio.h"
51#include "bcm43xx_power.h"
52#include "bcm43xx_wx.h"
Michael Buesch6465ce12006-02-02 19:11:08 +010053#include "bcm43xx_ethtool.h"
Michael Bueschf398f022006-02-23 21:15:39 +010054#include "bcm43xx_xmit.h"
John W. Linvillef2223132006-01-23 16:59:58 -050055
56
57MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
58MODULE_AUTHOR("Martin Langer");
59MODULE_AUTHOR("Stefano Brivio");
60MODULE_AUTHOR("Michael Buesch");
61MODULE_LICENSE("GPL");
62
63#ifdef CONFIG_BCM947XX
64extern char *nvram_get(char *name);
65#endif
66
Michael Buesch77db31e2006-02-12 16:47:44 +010067#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
John W. Linvillef2223132006-01-23 16:59:58 -050068static int modparam_pio;
69module_param_named(pio, modparam_pio, int, 0444);
70MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
Michael Buesch77db31e2006-02-12 16:47:44 +010071#elif defined(CONFIG_BCM43XX_DMA)
72# define modparam_pio 0
73#elif defined(CONFIG_BCM43XX_PIO)
74# define modparam_pio 1
75#endif
John W. Linvillef2223132006-01-23 16:59:58 -050076
77static int modparam_bad_frames_preempt;
78module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
79MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
80
81static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
82module_param_named(short_retry, modparam_short_retry, int, 0444);
83MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
84
85static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
86module_param_named(long_retry, modparam_long_retry, int, 0444);
87MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
88
89static int modparam_locale = -1;
90module_param_named(locale, modparam_locale, int, 0444);
91MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
92
John W. Linvillef2223132006-01-23 16:59:58 -050093static int modparam_noleds;
94module_param_named(noleds, modparam_noleds, int, 0444);
95MODULE_PARM_DESC(noleds, "Turn off all LED activity");
96
97#ifdef CONFIG_BCM43XX_DEBUG
98static char modparam_fwpostfix[64];
99module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
100MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
101#else
102# define modparam_fwpostfix ""
103#endif /* CONFIG_BCM43XX_DEBUG*/
104
105
106/* If you want to debug with just a single device, enable this,
107 * where the string is the pci device ID (as given by the kernel's
108 * pci_name function) of the device to be used.
109 */
110//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0"
111
112/* If you want to enable printing of each MMIO access, enable this. */
113//#define DEBUG_ENABLE_MMIO_PRINT
114
115/* If you want to enable printing of MMIO access within
116 * ucode/pcm upload, initvals write, enable this.
117 */
118//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
119
120/* If you want to enable printing of PCI Config Space access, enable this */
121//#define DEBUG_ENABLE_PCILOG
122
123
Michael Buesch489423c2006-02-13 00:11:07 +0100124/* Detailed list maintained at:
125 * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
126 */
127 static struct pci_device_id bcm43xx_pci_tbl[] = {
128 /* Broadcom 4303 802.11b */
129 { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
130 /* Broadcom 4307 802.11b */
131 { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
132 /* Broadcom 4318 802.11b/g */
133 { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
134 /* Broadcom 4306 802.11b/g */
135 { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
136 /* Broadcom 4306 802.11a */
137// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
138 /* Broadcom 4309 802.11a/b/g */
139 { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
140 /* Broadcom 43XG 802.11b/g */
141 { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500142#ifdef CONFIG_BCM947XX
143 /* SB bus on BCM947xx */
144 { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
145#endif
Michael Buesch489423c2006-02-13 00:11:07 +0100146 { 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500147};
148MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
149
150static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
151{
152 u32 status;
153
154 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
155 if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
156 val = swab32(val);
157
158 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
Michael Buesch73733842006-03-12 19:44:29 +0100159 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500160 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
161}
162
163static inline
164void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
165 u16 routing, u16 offset)
166{
167 u32 control;
168
169 /* "offset" is the WORD offset. */
170
171 control = routing;
172 control <<= 16;
173 control |= offset;
174 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
175}
176
177u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
178 u16 routing, u16 offset)
179{
180 u32 ret;
181
182 if (routing == BCM43xx_SHM_SHARED) {
183 if (offset & 0x0003) {
184 /* Unaligned access */
185 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
186 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
187 ret <<= 16;
188 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
189 ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
190
191 return ret;
192 }
193 offset >>= 2;
194 }
195 bcm43xx_shm_control_word(bcm, routing, offset);
196 ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
197
198 return ret;
199}
200
201u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
202 u16 routing, u16 offset)
203{
204 u16 ret;
205
206 if (routing == BCM43xx_SHM_SHARED) {
207 if (offset & 0x0003) {
208 /* Unaligned access */
209 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
210 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
211
212 return ret;
213 }
214 offset >>= 2;
215 }
216 bcm43xx_shm_control_word(bcm, routing, offset);
217 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
218
219 return ret;
220}
221
222void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
223 u16 routing, u16 offset,
224 u32 value)
225{
226 if (routing == BCM43xx_SHM_SHARED) {
227 if (offset & 0x0003) {
228 /* Unaligned access */
229 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
Michael Buesch73733842006-03-12 19:44:29 +0100230 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500231 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
232 (value >> 16) & 0xffff);
Michael Buesch73733842006-03-12 19:44:29 +0100233 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500234 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
Michael Buesch73733842006-03-12 19:44:29 +0100235 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500236 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA,
237 value & 0xffff);
238 return;
239 }
240 offset >>= 2;
241 }
242 bcm43xx_shm_control_word(bcm, routing, offset);
Michael Buesch73733842006-03-12 19:44:29 +0100243 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500244 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
245}
246
247void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
248 u16 routing, u16 offset,
249 u16 value)
250{
251 if (routing == BCM43xx_SHM_SHARED) {
252 if (offset & 0x0003) {
253 /* Unaligned access */
254 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
Michael Buesch73733842006-03-12 19:44:29 +0100255 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500256 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
257 value);
258 return;
259 }
260 offset >>= 2;
261 }
262 bcm43xx_shm_control_word(bcm, routing, offset);
Michael Buesch73733842006-03-12 19:44:29 +0100263 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500264 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);
265}
266
267void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf)
268{
269 /* We need to be careful. As we read the TSF from multiple
270 * registers, we should take care of register overflows.
271 * In theory, the whole tsf read process should be atomic.
272 * We try to be atomic here, by restaring the read process,
273 * if any of the high registers changed (overflew).
274 */
275 if (bcm->current_core->rev >= 3) {
276 u32 low, high, high2;
277
278 do {
279 high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
280 low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW);
281 high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
282 } while (unlikely(high != high2));
283
284 *tsf = high;
285 *tsf <<= 32;
286 *tsf |= low;
287 } else {
288 u64 tmp;
289 u16 v0, v1, v2, v3;
290 u16 test1, test2, test3;
291
292 do {
293 v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
294 v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
295 v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
296 v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0);
297
298 test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
299 test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
300 test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
301 } while (v3 != test3 || v2 != test2 || v1 != test1);
302
303 *tsf = v3;
304 *tsf <<= 48;
305 tmp = v2;
306 tmp <<= 32;
307 *tsf |= tmp;
308 tmp = v1;
309 tmp <<= 16;
310 *tsf |= tmp;
311 *tsf |= v0;
312 }
313}
314
315void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
316{
317 u32 status;
318
319 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
320 status |= BCM43xx_SBF_TIME_UPDATE;
321 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
Michael Buesch73733842006-03-12 19:44:29 +0100322 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500323
324 /* Be careful with the in-progress timer.
325 * First zero out the low register, so we have a full
326 * register-overflow duration to complete the operation.
327 */
328 if (bcm->current_core->rev >= 3) {
329 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
330 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
331
John W. Linvillef2223132006-01-23 16:59:58 -0500332 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
Michael Buesch73733842006-03-12 19:44:29 +0100333 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500334 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
Michael Buesch73733842006-03-12 19:44:29 +0100335 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500336 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
337 } else {
338 u16 v0 = (tsf & 0x000000000000FFFFULL);
339 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
340 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
341 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
342
John W. Linvillef2223132006-01-23 16:59:58 -0500343 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
Michael Buesch73733842006-03-12 19:44:29 +0100344 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500345 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
Michael Buesch73733842006-03-12 19:44:29 +0100346 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500347 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
Michael Buesch73733842006-03-12 19:44:29 +0100348 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500349 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
Michael Buesch73733842006-03-12 19:44:29 +0100350 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500351 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
352 }
353
354 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
355 status &= ~BCM43xx_SBF_TIME_UPDATE;
356 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
357}
358
John W. Linvillef2223132006-01-23 16:59:58 -0500359static
360void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
361 u16 offset,
362 const u8 *mac)
363{
364 u16 data;
365
366 offset |= 0x0020;
367 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
368
369 data = mac[0];
370 data |= mac[1] << 8;
371 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
372 data = mac[2];
373 data |= mac[3] << 8;
374 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
375 data = mac[4];
376 data |= mac[5] << 8;
377 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
378}
379
Michael Buesch489423c2006-02-13 00:11:07 +0100380static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
381 u16 offset)
John W. Linvillef2223132006-01-23 16:59:58 -0500382{
383 const u8 zero_addr[ETH_ALEN] = { 0 };
384
385 bcm43xx_macfilter_set(bcm, offset, zero_addr);
386}
387
388static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
389{
390 const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
391 const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
392 u8 mac_bssid[ETH_ALEN * 2];
393 int i;
394
395 memcpy(mac_bssid, mac, ETH_ALEN);
396 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
397
398 /* Write our MAC address and BSSID to template ram */
399 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
400 bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
401 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
402 bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
403 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
404 bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
405}
406
Michael Bueschb5e868e2006-03-25 16:27:32 +0100407//FIXME: Well, we should probably call them from somewhere.
408#if 0
Michael Buesch489423c2006-02-13 00:11:07 +0100409static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
John W. Linvillef2223132006-01-23 16:59:58 -0500410{
411 /* slot_time is in usec. */
Michael Buesche9357c02006-03-13 19:27:34 +0100412 if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G)
John W. Linvillef2223132006-01-23 16:59:58 -0500413 return;
414 bcm43xx_write16(bcm, 0x684, 510 + slot_time);
415 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
416}
417
Michael Buesch489423c2006-02-13 00:11:07 +0100418static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500419{
420 bcm43xx_set_slot_time(bcm, 9);
421}
422
Michael Buesch489423c2006-02-13 00:11:07 +0100423static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500424{
425 bcm43xx_set_slot_time(bcm, 20);
426}
Michael Bueschb5e868e2006-03-25 16:27:32 +0100427#endif
John W. Linvillef2223132006-01-23 16:59:58 -0500428
Michael Bueschb5e868e2006-03-25 16:27:32 +0100429/* FIXME: To get the MAC-filter working, we need to implement the
430 * following functions (and rename them :)
431 */
432#if 0
John W. Linvillef2223132006-01-23 16:59:58 -0500433static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
434{
435 bcm43xx_mac_suspend(bcm);
436 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
437
438 bcm43xx_ram_write(bcm, 0x0026, 0x0000);
439 bcm43xx_ram_write(bcm, 0x0028, 0x0000);
440 bcm43xx_ram_write(bcm, 0x007E, 0x0000);
441 bcm43xx_ram_write(bcm, 0x0080, 0x0000);
442 bcm43xx_ram_write(bcm, 0x047E, 0x0000);
443 bcm43xx_ram_write(bcm, 0x0480, 0x0000);
444
445 if (bcm->current_core->rev < 3) {
446 bcm43xx_write16(bcm, 0x0610, 0x8000);
447 bcm43xx_write16(bcm, 0x060E, 0x0000);
448 } else
449 bcm43xx_write32(bcm, 0x0188, 0x80000000);
450
451 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
452
Michael Buesche9357c02006-03-13 19:27:34 +0100453 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G &&
John W. Linvillef2223132006-01-23 16:59:58 -0500454 ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
455 bcm43xx_short_slot_timing_enable(bcm);
456
457 bcm43xx_mac_enable(bcm);
458}
459
John W. Linvillef2223132006-01-23 16:59:58 -0500460static void bcm43xx_associate(struct bcm43xx_private *bcm,
461 const u8 *mac)
462{
463 memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
464
465 bcm43xx_mac_suspend(bcm);
466 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
467 bcm43xx_write_mac_bssid_templates(bcm);
468 bcm43xx_mac_enable(bcm);
469}
Michael Bueschb5e868e2006-03-25 16:27:32 +0100470#endif
John W. Linvillef2223132006-01-23 16:59:58 -0500471
472/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
473 * Returns the _previously_ enabled IRQ mask.
474 */
475static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
476{
477 u32 old_mask;
478
479 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
480 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
481
482 return old_mask;
483}
484
485/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
486 * Returns the _previously_ enabled IRQ mask.
487 */
488static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
489{
490 u32 old_mask;
491
492 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
493 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
494
495 return old_mask;
496}
497
498/* Make sure we don't receive more data from the device. */
499static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
500{
501 u32 old;
502 unsigned long flags;
503
Michael Bueschefccb642006-03-11 13:39:14 +0100504 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500505 if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
Michael Bueschefccb642006-03-11 13:39:14 +0100506 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500507 return -EBUSY;
508 }
509 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
510 tasklet_disable(&bcm->isr_tasklet);
Michael Bueschefccb642006-03-11 13:39:14 +0100511 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500512 if (oldstate)
513 *oldstate = old;
514
515 return 0;
516}
517
518static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
519{
Michael Buesche9357c02006-03-13 19:27:34 +0100520 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
521 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -0500522 u32 radio_id;
523 u16 manufact;
524 u16 version;
525 u8 revision;
526 s8 i;
527
528 if (bcm->chip_id == 0x4317) {
529 if (bcm->chip_rev == 0x00)
530 radio_id = 0x3205017F;
531 else if (bcm->chip_rev == 0x01)
532 radio_id = 0x4205017F;
533 else
534 radio_id = 0x5205017F;
535 } else {
536 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
537 radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
538 radio_id <<= 16;
539 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
540 radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
541 }
542
543 manufact = (radio_id & 0x00000FFF);
544 version = (radio_id & 0x0FFFF000) >> 12;
545 revision = (radio_id & 0xF0000000) >> 28;
546
Michael Buesch489423c2006-02-13 00:11:07 +0100547 dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
John W. Linvillef2223132006-01-23 16:59:58 -0500548 radio_id, manufact, version, revision);
549
Michael Buesch489423c2006-02-13 00:11:07 +0100550 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -0500551 case BCM43xx_PHYTYPE_A:
552 if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
553 goto err_unsupported_radio;
554 break;
555 case BCM43xx_PHYTYPE_B:
556 if ((version & 0xFFF0) != 0x2050)
557 goto err_unsupported_radio;
558 break;
559 case BCM43xx_PHYTYPE_G:
560 if (version != 0x2050)
561 goto err_unsupported_radio;
562 break;
563 }
564
Michael Buesch489423c2006-02-13 00:11:07 +0100565 radio->manufact = manufact;
566 radio->version = version;
567 radio->revision = revision;
John W. Linvillef2223132006-01-23 16:59:58 -0500568
569 /* Set default attenuation values. */
Michael Buesch6ecb2692006-03-20 00:01:04 +0100570 radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
571 radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
572 radio->txctl1 = bcm43xx_default_txctl1(bcm);
Michael Bueschadc40e92006-03-25 20:36:57 +0100573 radio->txctl2 = 0xFFFF;
Michael Buesche9357c02006-03-13 19:27:34 +0100574 if (phy->type == BCM43xx_PHYTYPE_A)
Michael Buesch489423c2006-02-13 00:11:07 +0100575 radio->txpower_desired = bcm->sprom.maxpower_aphy;
Michael Buesch393344f2006-02-05 15:28:20 +0100576 else
Michael Buesche9357c02006-03-13 19:27:34 +0100577 radio->txpower_desired = bcm->sprom.maxpower_bgphy;
John W. Linvillef2223132006-01-23 16:59:58 -0500578
579 /* Initialize the in-memory nrssi Lookup Table. */
580 for (i = 0; i < 64; i++)
Michael Buesch489423c2006-02-13 00:11:07 +0100581 radio->nrssi_lt[i] = i;
John W. Linvillef2223132006-01-23 16:59:58 -0500582
583 return 0;
584
585err_unsupported_radio:
586 printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
587 return -ENODEV;
588}
589
590static const char * bcm43xx_locale_iso(u8 locale)
591{
592 /* ISO 3166-1 country codes.
593 * Note that there aren't ISO 3166-1 codes for
594 * all or locales. (Not all locales are countries)
595 */
596 switch (locale) {
597 case BCM43xx_LOCALE_WORLD:
598 case BCM43xx_LOCALE_ALL:
599 return "XX";
600 case BCM43xx_LOCALE_THAILAND:
601 return "TH";
602 case BCM43xx_LOCALE_ISRAEL:
603 return "IL";
604 case BCM43xx_LOCALE_JORDAN:
605 return "JO";
606 case BCM43xx_LOCALE_CHINA:
607 return "CN";
608 case BCM43xx_LOCALE_JAPAN:
609 case BCM43xx_LOCALE_JAPAN_HIGH:
610 return "JP";
611 case BCM43xx_LOCALE_USA_CANADA_ANZ:
612 case BCM43xx_LOCALE_USA_LOW:
613 return "US";
614 case BCM43xx_LOCALE_EUROPE:
615 return "EU";
616 case BCM43xx_LOCALE_NONE:
617 return " ";
618 }
619 assert(0);
620 return " ";
621}
622
623static const char * bcm43xx_locale_string(u8 locale)
624{
625 switch (locale) {
626 case BCM43xx_LOCALE_WORLD:
627 return "World";
628 case BCM43xx_LOCALE_THAILAND:
629 return "Thailand";
630 case BCM43xx_LOCALE_ISRAEL:
631 return "Israel";
632 case BCM43xx_LOCALE_JORDAN:
633 return "Jordan";
634 case BCM43xx_LOCALE_CHINA:
635 return "China";
636 case BCM43xx_LOCALE_JAPAN:
637 return "Japan";
638 case BCM43xx_LOCALE_USA_CANADA_ANZ:
639 return "USA/Canada/ANZ";
640 case BCM43xx_LOCALE_EUROPE:
641 return "Europe";
642 case BCM43xx_LOCALE_USA_LOW:
643 return "USAlow";
644 case BCM43xx_LOCALE_JAPAN_HIGH:
645 return "JapanHigh";
646 case BCM43xx_LOCALE_ALL:
647 return "All";
648 case BCM43xx_LOCALE_NONE:
649 return "None";
650 }
651 assert(0);
652 return "";
653}
654
655static inline u8 bcm43xx_crc8(u8 crc, u8 data)
656{
657 static const u8 t[] = {
658 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
659 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
660 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
661 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
662 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
663 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
664 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
665 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
666 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
667 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
668 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
669 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
670 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
671 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
672 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
673 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
674 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
675 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
676 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
677 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
678 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
679 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
680 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
681 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
682 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
683 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
684 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
685 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
686 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
687 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
688 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
689 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
690 };
691 return t[crc ^ data];
692}
693
Michael Bueschad3f0862006-02-19 14:12:22 +0100694static u8 bcm43xx_sprom_crc(const u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500695{
696 int word;
697 u8 crc = 0xFF;
698
699 for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
700 crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
701 crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
702 }
703 crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
704 crc ^= 0xFF;
705
706 return crc;
707}
708
Michael Bueschea0922b2006-02-19 14:09:20 +0100709int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500710{
711 int i;
Michael Bueschea0922b2006-02-19 14:09:20 +0100712 u8 crc, expected_crc;
713
714 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
715 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
716 /* CRC-8 check. */
717 crc = bcm43xx_sprom_crc(sprom);
718 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
719 if (crc != expected_crc) {
720 printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
721 "(0x%02X, expected: 0x%02X)\n",
722 crc, expected_crc);
723 return -EINVAL;
724 }
725
726 return 0;
727}
728
729int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
730{
731 int i, err;
732 u8 crc, expected_crc;
733 u32 spromctl;
734
735 /* CRC-8 validation of the input data. */
736 crc = bcm43xx_sprom_crc(sprom);
737 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
738 if (crc != expected_crc) {
739 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
740 return -EINVAL;
741 }
742
743 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
744 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
745 if (err)
746 goto err_ctlreg;
747 spromctl |= 0x10; /* SPROM WRITE enable. */
748 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
749 if (err)
750 goto err_ctlreg;
751 /* We must burn lots of CPU cycles here, but that does not
752 * really matter as one does not write the SPROM every other minute...
753 */
754 printk(KERN_INFO PFX "[ 0%%");
755 mdelay(500);
756 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
757 if (i == 16)
758 printk("25%%");
759 else if (i == 32)
760 printk("50%%");
761 else if (i == 48)
762 printk("75%%");
763 else if (i % 2)
764 printk(".");
765 bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
Michael Bueschefccb642006-03-11 13:39:14 +0100766 mmiowb();
Michael Bueschea0922b2006-02-19 14:09:20 +0100767 mdelay(20);
768 }
769 spromctl &= ~0x10; /* SPROM WRITE enable. */
770 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
771 if (err)
772 goto err_ctlreg;
773 mdelay(500);
774 printk("100%% ]\n");
775 printk(KERN_INFO PFX "SPROM written.\n");
776 bcm43xx_controller_restart(bcm, "SPROM update");
777
778 return 0;
779err_ctlreg:
780 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
781 return -ENODEV;
782}
783
784static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
785{
John W. Linvillef2223132006-01-23 16:59:58 -0500786 u16 value;
787 u16 *sprom;
John W. Linvillef2223132006-01-23 16:59:58 -0500788#ifdef CONFIG_BCM947XX
789 char *c;
790#endif
791
792 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
793 GFP_KERNEL);
794 if (!sprom) {
Michael Bueschea0922b2006-02-19 14:09:20 +0100795 printk(KERN_ERR PFX "sprom_extract OOM\n");
John W. Linvillef2223132006-01-23 16:59:58 -0500796 return -ENOMEM;
797 }
798#ifdef CONFIG_BCM947XX
799 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
800 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
801
802 if ((c = nvram_get("il0macaddr")) != NULL)
803 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
804
805 if ((c = nvram_get("et1macaddr")) != NULL)
806 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
807
808 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
809 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
810 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
811
812 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
813 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
814 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
815
816 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
817#else
Michael Bueschea0922b2006-02-19 14:09:20 +0100818 bcm43xx_sprom_read(bcm, sprom);
John W. Linvillef2223132006-01-23 16:59:58 -0500819#endif
820
821 /* boardflags2 */
822 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
823 bcm->sprom.boardflags2 = value;
824
825 /* il0macaddr */
826 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
827 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
828 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
829 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
830 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
831 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
832
833 /* et0macaddr */
834 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
835 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
836 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
837 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
838 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
839 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
840
841 /* et1macaddr */
842 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
843 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
844 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
845 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
846 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
847 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
848
849 /* ethernet phy settings */
850 value = sprom[BCM43xx_SPROM_ETHPHY];
851 bcm->sprom.et0phyaddr = (value & 0x001F);
852 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
853 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
854 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
855
856 /* boardrev, antennas, locale */
857 value = sprom[BCM43xx_SPROM_BOARDREV];
858 bcm->sprom.boardrev = (value & 0x00FF);
859 bcm->sprom.locale = (value & 0x0F00) >> 8;
860 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
861 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
862 if (modparam_locale != -1) {
863 if (modparam_locale >= 0 && modparam_locale <= 11) {
864 bcm->sprom.locale = modparam_locale;
865 printk(KERN_WARNING PFX "Operating with modified "
866 "LocaleCode %u (%s)\n",
867 bcm->sprom.locale,
868 bcm43xx_locale_string(bcm->sprom.locale));
869 } else {
870 printk(KERN_WARNING PFX "Module parameter \"locale\" "
871 "invalid value. (0 - 11)\n");
872 }
873 }
874
875 /* pa0b* */
876 value = sprom[BCM43xx_SPROM_PA0B0];
877 bcm->sprom.pa0b0 = value;
878 value = sprom[BCM43xx_SPROM_PA0B1];
879 bcm->sprom.pa0b1 = value;
880 value = sprom[BCM43xx_SPROM_PA0B2];
881 bcm->sprom.pa0b2 = value;
882
883 /* wl0gpio* */
884 value = sprom[BCM43xx_SPROM_WL0GPIO0];
885 if (value == 0x0000)
886 value = 0xFFFF;
887 bcm->sprom.wl0gpio0 = value & 0x00FF;
888 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
889 value = sprom[BCM43xx_SPROM_WL0GPIO2];
890 if (value == 0x0000)
891 value = 0xFFFF;
892 bcm->sprom.wl0gpio2 = value & 0x00FF;
893 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
894
895 /* maxpower */
896 value = sprom[BCM43xx_SPROM_MAXPWR];
897 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
898 bcm->sprom.maxpower_bgphy = value & 0x00FF;
899
900 /* pa1b* */
901 value = sprom[BCM43xx_SPROM_PA1B0];
902 bcm->sprom.pa1b0 = value;
903 value = sprom[BCM43xx_SPROM_PA1B1];
904 bcm->sprom.pa1b1 = value;
905 value = sprom[BCM43xx_SPROM_PA1B2];
906 bcm->sprom.pa1b2 = value;
907
908 /* idle tssi target */
909 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
910 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
911 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
912
913 /* boardflags */
914 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
915 if (value == 0xFFFF)
916 value = 0x0000;
917 bcm->sprom.boardflags = value;
Michael Bueschb3db5e52006-03-15 16:31:45 +0100918 /* boardflags workarounds */
919 if (bcm->board_vendor == PCI_VENDOR_ID_DELL &&
920 bcm->chip_id == 0x4301 &&
921 bcm->board_revision == 0x74)
922 bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST;
923 if (bcm->board_vendor == PCI_VENDOR_ID_APPLE &&
924 bcm->board_type == 0x4E &&
925 bcm->board_revision > 0x40)
926 bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL;
John W. Linvillef2223132006-01-23 16:59:58 -0500927
928 /* antenna gain */
929 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
930 if (value == 0x0000 || value == 0xFFFF)
931 value = 0x0202;
932 /* convert values to Q5.2 */
933 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
934 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
935
936 kfree(sprom);
937
938 return 0;
939}
940
John W. Linvillef2223132006-01-23 16:59:58 -0500941static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
942{
943 struct ieee80211_geo geo;
944 struct ieee80211_channel *chan;
945 int have_a = 0, have_bg = 0;
Michael Buesche9357c02006-03-13 19:27:34 +0100946 int i;
Michael Buesch9e4a3752006-02-02 18:43:25 +0100947 u8 channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500948 struct bcm43xx_phyinfo *phy;
949 const char *iso_country;
950
951 memset(&geo, 0, sizeof(geo));
Michael Buesche9357c02006-03-13 19:27:34 +0100952 for (i = 0; i < bcm->nr_80211_available; i++) {
953 phy = &(bcm->core_80211_ext[i].phy);
John W. Linvillef2223132006-01-23 16:59:58 -0500954 switch (phy->type) {
955 case BCM43xx_PHYTYPE_B:
956 case BCM43xx_PHYTYPE_G:
957 have_bg = 1;
958 break;
959 case BCM43xx_PHYTYPE_A:
960 have_a = 1;
961 break;
962 default:
963 assert(0);
964 }
965 }
966 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
967
968 if (have_a) {
969 for (i = 0, channel = 0; channel < 201; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500970 chan = &geo.a[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100971 chan->freq = bcm43xx_channel_to_freq_a(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500972 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500973 }
974 geo.a_channels = i;
975 }
976 if (have_bg) {
977 for (i = 0, channel = 1; channel < 15; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500978 chan = &geo.bg[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100979 chan->freq = bcm43xx_channel_to_freq_bg(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500980 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500981 }
982 geo.bg_channels = i;
983 }
984 memcpy(geo.name, iso_country, 2);
985 if (0 /*TODO: Outdoor use only */)
986 geo.name[2] = 'O';
987 else if (0 /*TODO: Indoor use only */)
988 geo.name[2] = 'I';
989 else
990 geo.name[2] = ' ';
991 geo.name[3] = '\0';
992
993 ieee80211_set_geo(bcm->ieee, &geo);
994}
995
996/* DummyTransmission function, as documented on
997 * http://bcm-specs.sipsolutions.net/DummyTransmission
998 */
999void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
1000{
Michael Buesche9357c02006-03-13 19:27:34 +01001001 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1002 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001003 unsigned int i, max_loop;
1004 u16 value = 0;
1005 u32 buffer[5] = {
1006 0x00000000,
1007 0x0000D400,
1008 0x00000000,
1009 0x00000001,
1010 0x00000000,
1011 };
1012
Michael Buesch489423c2006-02-13 00:11:07 +01001013 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -05001014 case BCM43xx_PHYTYPE_A:
1015 max_loop = 0x1E;
1016 buffer[0] = 0xCC010200;
1017 break;
1018 case BCM43xx_PHYTYPE_B:
1019 case BCM43xx_PHYTYPE_G:
1020 max_loop = 0xFA;
1021 buffer[0] = 0x6E840B00;
1022 break;
1023 default:
1024 assert(0);
1025 return;
1026 }
1027
1028 for (i = 0; i < 5; i++)
1029 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1030
1031 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1032
1033 bcm43xx_write16(bcm, 0x0568, 0x0000);
1034 bcm43xx_write16(bcm, 0x07C0, 0x0000);
Michael Buesch489423c2006-02-13 00:11:07 +01001035 bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
John W. Linvillef2223132006-01-23 16:59:58 -05001036 bcm43xx_write16(bcm, 0x0508, 0x0000);
1037 bcm43xx_write16(bcm, 0x050A, 0x0000);
1038 bcm43xx_write16(bcm, 0x054C, 0x0000);
1039 bcm43xx_write16(bcm, 0x056A, 0x0014);
1040 bcm43xx_write16(bcm, 0x0568, 0x0826);
1041 bcm43xx_write16(bcm, 0x0500, 0x0000);
1042 bcm43xx_write16(bcm, 0x0502, 0x0030);
1043
Michael Buesch73733842006-03-12 19:44:29 +01001044 if (radio->version == 0x2050 && radio->revision <= 0x5)
1045 bcm43xx_radio_write16(bcm, 0x0051, 0x0017);
John W. Linvillef2223132006-01-23 16:59:58 -05001046 for (i = 0x00; i < max_loop; i++) {
1047 value = bcm43xx_read16(bcm, 0x050E);
Michael Buesch73733842006-03-12 19:44:29 +01001048 if (value & 0x0080)
John W. Linvillef2223132006-01-23 16:59:58 -05001049 break;
1050 udelay(10);
1051 }
1052 for (i = 0x00; i < 0x0A; i++) {
1053 value = bcm43xx_read16(bcm, 0x050E);
Michael Buesch73733842006-03-12 19:44:29 +01001054 if (value & 0x0400)
John W. Linvillef2223132006-01-23 16:59:58 -05001055 break;
1056 udelay(10);
1057 }
1058 for (i = 0x00; i < 0x0A; i++) {
1059 value = bcm43xx_read16(bcm, 0x0690);
Michael Buesch73733842006-03-12 19:44:29 +01001060 if (!(value & 0x0100))
John W. Linvillef2223132006-01-23 16:59:58 -05001061 break;
1062 udelay(10);
1063 }
Michael Buesch73733842006-03-12 19:44:29 +01001064 if (radio->version == 0x2050 && radio->revision <= 0x5)
1065 bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
John W. Linvillef2223132006-01-23 16:59:58 -05001066}
1067
1068static void key_write(struct bcm43xx_private *bcm,
1069 u8 index, u8 algorithm, const u16 *key)
1070{
1071 unsigned int i, basic_wep = 0;
1072 u32 offset;
1073 u16 value;
1074
1075 /* Write associated key information */
1076 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1077 ((index << 4) | (algorithm & 0x0F)));
1078
1079 /* The first 4 WEP keys need extra love */
1080 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1081 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1082 basic_wep = 1;
1083
1084 /* Write key payload, 8 little endian words */
1085 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1086 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1087 value = cpu_to_le16(key[i]);
1088 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1089 offset + (i * 2), value);
1090
1091 if (!basic_wep)
1092 continue;
1093
1094 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1095 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1096 value);
1097 }
1098}
1099
1100static void keymac_write(struct bcm43xx_private *bcm,
1101 u8 index, const u32 *addr)
1102{
1103 /* for keys 0-3 there is no associated mac address */
1104 if (index < 4)
1105 return;
1106
1107 index -= 4;
1108 if (bcm->current_core->rev >= 5) {
1109 bcm43xx_shm_write32(bcm,
1110 BCM43xx_SHM_HWMAC,
1111 index * 2,
1112 cpu_to_be32(*addr));
1113 bcm43xx_shm_write16(bcm,
1114 BCM43xx_SHM_HWMAC,
1115 (index * 2) + 1,
1116 cpu_to_be16(*((u16 *)(addr + 1))));
1117 } else {
1118 if (index < 8) {
1119 TODO(); /* Put them in the macaddress filter */
1120 } else {
1121 TODO();
1122 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1123 Keep in mind to update the count of keymacs in 0x003E as well! */
1124 }
1125 }
1126}
1127
1128static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1129 u8 index, u8 algorithm,
1130 const u8 *_key, int key_len,
1131 const u8 *mac_addr)
1132{
1133 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1134
1135 if (index >= ARRAY_SIZE(bcm->key))
1136 return -EINVAL;
1137 if (key_len > ARRAY_SIZE(key))
1138 return -EINVAL;
1139 if (algorithm < 1 || algorithm > 5)
1140 return -EINVAL;
1141
1142 memcpy(key, _key, key_len);
1143 key_write(bcm, index, algorithm, (const u16 *)key);
1144 keymac_write(bcm, index, (const u32 *)mac_addr);
1145
1146 bcm->key[index].algorithm = algorithm;
1147
1148 return 0;
1149}
1150
1151static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1152{
1153 static const u32 zero_mac[2] = { 0 };
1154 unsigned int i,j, nr_keys = 54;
1155 u16 offset;
1156
1157 if (bcm->current_core->rev < 5)
1158 nr_keys = 16;
1159 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1160
1161 for (i = 0; i < nr_keys; i++) {
1162 bcm->key[i].enabled = 0;
1163 /* returns for i < 4 immediately */
1164 keymac_write(bcm, i, zero_mac);
1165 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1166 0x100 + (i * 2), 0x0000);
1167 for (j = 0; j < 8; j++) {
1168 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1169 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1170 offset, 0x0000);
1171 }
1172 }
1173 dprintk(KERN_INFO PFX "Keys cleared\n");
1174}
1175
John W. Linvillef2223132006-01-23 16:59:58 -05001176/* Lowlevel core-switch function. This is only to be used in
1177 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1178 */
1179static int _switch_core(struct bcm43xx_private *bcm, int core)
1180{
1181 int err;
1182 int attempts = 0;
Michael Buesch489423c2006-02-13 00:11:07 +01001183 u32 current_core;
John W. Linvillef2223132006-01-23 16:59:58 -05001184
1185 assert(core >= 0);
Michael Buesch489423c2006-02-13 00:11:07 +01001186 while (1) {
1187 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
John W. Linvillef2223132006-01-23 16:59:58 -05001188 (core * 0x1000) + 0x18000000);
Michael Buesch489423c2006-02-13 00:11:07 +01001189 if (unlikely(err))
1190 goto error;
1191 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1192 &current_core);
1193 if (unlikely(err))
1194 goto error;
1195 current_core = (current_core - 0x18000000) / 0x1000;
1196 if (current_core == core)
1197 break;
John W. Linvillef2223132006-01-23 16:59:58 -05001198
Michael Buesch489423c2006-02-13 00:11:07 +01001199 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
1200 goto error;
1201 udelay(10);
1202 }
1203#ifdef CONFIG_BCM947XX
1204 if (bcm->pci_dev->bus->number == 0)
1205 bcm->current_core_offset = 0x1000 * core;
1206 else
1207 bcm->current_core_offset = 0;
1208#endif
1209
1210 return 0;
1211error:
1212 printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
1213 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05001214}
1215
1216int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1217{
1218 int err;
1219
Michael Buesch489423c2006-02-13 00:11:07 +01001220 if (unlikely(!new_core))
John W. Linvillef2223132006-01-23 16:59:58 -05001221 return 0;
Michael Buesche9357c02006-03-13 19:27:34 +01001222 if (!new_core->available)
John W. Linvillef2223132006-01-23 16:59:58 -05001223 return -ENODEV;
1224 if (bcm->current_core == new_core)
1225 return 0;
1226 err = _switch_core(bcm, new_core->index);
Michael Buesche9357c02006-03-13 19:27:34 +01001227 if (unlikely(err))
1228 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001229
Michael Buesche9357c02006-03-13 19:27:34 +01001230 bcm->current_core = new_core;
1231 bcm->current_80211_core_idx = -1;
1232 if (new_core->id == BCM43xx_COREID_80211)
1233 bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
1234
1235out:
John W. Linvillef2223132006-01-23 16:59:58 -05001236 return err;
1237}
1238
Michael Buesch489423c2006-02-13 00:11:07 +01001239static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001240{
1241 u32 value;
1242
1243 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1244 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1245 | BCM43xx_SBTMSTATELOW_REJECT;
1246
1247 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1248}
1249
1250/* disable current core */
1251static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1252{
1253 u32 sbtmstatelow;
1254 u32 sbtmstatehigh;
1255 int i;
1256
1257 /* fetch sbtmstatelow from core information registers */
1258 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1259
1260 /* core is already in reset */
1261 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1262 goto out;
1263
1264 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1265 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1266 BCM43xx_SBTMSTATELOW_REJECT;
1267 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1268
1269 for (i = 0; i < 1000; i++) {
1270 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1271 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1272 i = -1;
1273 break;
1274 }
1275 udelay(10);
1276 }
1277 if (i != -1) {
1278 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1279 return -EBUSY;
1280 }
1281
1282 for (i = 0; i < 1000; i++) {
1283 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1284 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1285 i = -1;
1286 break;
1287 }
1288 udelay(10);
1289 }
1290 if (i != -1) {
1291 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1292 return -EBUSY;
1293 }
1294
1295 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1296 BCM43xx_SBTMSTATELOW_REJECT |
1297 BCM43xx_SBTMSTATELOW_RESET |
1298 BCM43xx_SBTMSTATELOW_CLOCK |
1299 core_flags;
1300 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1301 udelay(10);
1302 }
1303
1304 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1305 BCM43xx_SBTMSTATELOW_REJECT |
1306 core_flags;
1307 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1308
1309out:
Michael Buesche9357c02006-03-13 19:27:34 +01001310 bcm->current_core->enabled = 0;
1311
John W. Linvillef2223132006-01-23 16:59:58 -05001312 return 0;
1313}
1314
1315/* enable (reset) current core */
1316static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1317{
1318 u32 sbtmstatelow;
1319 u32 sbtmstatehigh;
1320 u32 sbimstate;
1321 int err;
1322
1323 err = bcm43xx_core_disable(bcm, core_flags);
1324 if (err)
1325 goto out;
1326
1327 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1328 BCM43xx_SBTMSTATELOW_RESET |
1329 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1330 core_flags;
1331 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1332 udelay(1);
1333
1334 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1335 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1336 sbtmstatehigh = 0x00000000;
1337 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1338 }
1339
1340 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1341 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1342 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1343 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1344 }
1345
1346 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1347 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1348 core_flags;
1349 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1350 udelay(1);
1351
1352 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1353 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1354 udelay(1);
1355
Michael Buesche9357c02006-03-13 19:27:34 +01001356 bcm->current_core->enabled = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001357 assert(err == 0);
1358out:
1359 return err;
1360}
1361
1362/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1363void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1364{
1365 u32 flags = 0x00040000;
1366
Michael Buesch77db31e2006-02-12 16:47:44 +01001367 if ((bcm43xx_core_enabled(bcm)) &&
1368 !bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05001369//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1370#ifndef CONFIG_BCM947XX
1371 /* reset all used DMA controllers. */
1372 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1373 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1374 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1375 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1376 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1377 if (bcm->current_core->rev < 5)
1378 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1379#endif
1380 }
1381 if (bcm->shutting_down) {
1382 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1383 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1384 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1385 } else {
1386 if (connect_phy)
1387 flags |= 0x20000000;
1388 bcm43xx_phy_connect(bcm, connect_phy);
1389 bcm43xx_core_enable(bcm, flags);
1390 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1391 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1392 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1393 | BCM43xx_SBF_400);
1394 }
1395}
1396
1397static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1398{
1399 bcm43xx_radio_turn_off(bcm);
1400 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1401 bcm43xx_core_disable(bcm, 0);
1402}
1403
1404/* Mark the current 80211 core inactive.
1405 * "active_80211_core" is the other 80211 core, which is used.
1406 */
1407static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1408 struct bcm43xx_coreinfo *active_80211_core)
1409{
1410 u32 sbtmstatelow;
1411 struct bcm43xx_coreinfo *old_core;
1412 int err = 0;
1413
1414 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1415 bcm43xx_radio_turn_off(bcm);
1416 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1417 sbtmstatelow &= ~0x200a0000;
1418 sbtmstatelow |= 0xa0000;
1419 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1420 udelay(1);
1421 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1422 sbtmstatelow &= ~0xa0000;
1423 sbtmstatelow |= 0x80000;
1424 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1425 udelay(1);
1426
Michael Buesche9357c02006-03-13 19:27:34 +01001427 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -05001428 old_core = bcm->current_core;
1429 err = bcm43xx_switch_core(bcm, active_80211_core);
1430 if (err)
1431 goto out;
1432 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1433 sbtmstatelow &= ~0x20000000;
1434 sbtmstatelow |= 0x20000000;
1435 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1436 err = bcm43xx_switch_core(bcm, old_core);
1437 }
1438
1439out:
1440 return err;
1441}
1442
Michael Buesch489423c2006-02-13 00:11:07 +01001443static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001444{
1445 u32 v0, v1;
1446 u16 tmp;
1447 struct bcm43xx_xmitstatus stat;
1448
John W. Linvillef2223132006-01-23 16:59:58 -05001449 while (1) {
1450 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1451 if (!v0)
1452 break;
1453 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1454
1455 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1456 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1457 stat.flags = tmp & 0xFF;
1458 stat.cnt1 = (tmp & 0x0F00) >> 8;
1459 stat.cnt2 = (tmp & 0xF000) >> 12;
1460 stat.seq = (u16)(v1 & 0xFFFF);
1461 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1462
1463 bcm43xx_debugfs_log_txstat(bcm, &stat);
1464
1465 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1466 continue;
1467 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1468 //TODO: packet was not acked (was lost)
1469 }
1470 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1471
Michael Buesch77db31e2006-02-12 16:47:44 +01001472 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001473 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1474 else
1475 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1476 }
1477}
1478
Michael Buesch489423c2006-02-13 00:11:07 +01001479static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001480{
1481 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1482 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1483 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1484 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1485 assert(bcm->noisecalc.core_at_start == bcm->current_core);
Michael Buesche9357c02006-03-13 19:27:34 +01001486 assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);
John W. Linvillef2223132006-01-23 16:59:58 -05001487}
1488
1489static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1490{
1491 /* Top half of Link Quality calculation. */
1492
1493 if (bcm->noisecalc.calculation_running)
1494 return;
1495 bcm->noisecalc.core_at_start = bcm->current_core;
Michael Buesche9357c02006-03-13 19:27:34 +01001496 bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;
John W. Linvillef2223132006-01-23 16:59:58 -05001497 bcm->noisecalc.calculation_running = 1;
1498 bcm->noisecalc.nr_samples = 0;
1499
1500 bcm43xx_generate_noise_sample(bcm);
1501}
1502
Michael Buesch489423c2006-02-13 00:11:07 +01001503static void handle_irq_noise(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001504{
Michael Buesche9357c02006-03-13 19:27:34 +01001505 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001506 u16 tmp;
1507 u8 noise[4];
1508 u8 i, j;
1509 s32 average;
1510
1511 /* Bottom half of Link Quality calculation. */
1512
1513 assert(bcm->noisecalc.calculation_running);
1514 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1515 bcm->noisecalc.channel_at_start != radio->channel)
1516 goto drop_calculation;
1517 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1518 noise[0] = (tmp & 0x00FF);
1519 noise[1] = (tmp & 0xFF00) >> 8;
1520 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1521 noise[2] = (tmp & 0x00FF);
1522 noise[3] = (tmp & 0xFF00) >> 8;
1523 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1524 noise[2] == 0x7F || noise[3] == 0x7F)
1525 goto generate_new;
1526
1527 /* Get the noise samples. */
1528 assert(bcm->noisecalc.nr_samples <= 8);
1529 i = bcm->noisecalc.nr_samples;
1530 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1531 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1532 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1533 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1534 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1535 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1536 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1537 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1538 bcm->noisecalc.nr_samples++;
1539 if (bcm->noisecalc.nr_samples == 8) {
1540 /* Calculate the Link Quality by the noise samples. */
1541 average = 0;
1542 for (i = 0; i < 8; i++) {
1543 for (j = 0; j < 4; j++)
1544 average += bcm->noisecalc.samples[i][j];
1545 }
1546 average /= (8 * 4);
1547 average *= 125;
1548 average += 64;
1549 average /= 128;
Michael Buesch72fb8512006-03-22 18:10:19 +01001550
John W. Linvillef2223132006-01-23 16:59:58 -05001551 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1552 tmp = (tmp / 128) & 0x1F;
1553 if (tmp >= 8)
1554 average += 2;
1555 else
1556 average -= 25;
1557 if (tmp == 8)
1558 average -= 72;
1559 else
1560 average -= 48;
1561
Michael Buesch72fb8512006-03-22 18:10:19 +01001562/* FIXME: This is wrong, but people want fancy stats. well... */
1563bcm->stats.noise = average;
John W. Linvillef2223132006-01-23 16:59:58 -05001564 if (average > -65)
1565 bcm->stats.link_quality = 0;
1566 else if (average > -75)
1567 bcm->stats.link_quality = 1;
1568 else if (average > -85)
1569 bcm->stats.link_quality = 2;
1570 else
1571 bcm->stats.link_quality = 3;
1572// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1573drop_calculation:
1574 bcm->noisecalc.calculation_running = 0;
1575 return;
1576 }
1577generate_new:
1578 bcm43xx_generate_noise_sample(bcm);
1579}
1580
Michael Buesch489423c2006-02-13 00:11:07 +01001581static void handle_irq_ps(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001582{
1583 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1584 ///TODO: PS TBTT
1585 } else {
1586 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1587 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1588 }
1589 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1590 bcm->reg124_set_0x4 = 1;
1591 //FIXME else set to false?
1592}
1593
Michael Buesch489423c2006-02-13 00:11:07 +01001594static void handle_irq_reg124(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001595{
1596 if (!bcm->reg124_set_0x4)
1597 return;
1598 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1599 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1600 | 0x4);
1601 //FIXME: reset reg124_set_0x4 to false?
1602}
1603
Michael Buesch489423c2006-02-13 00:11:07 +01001604static void handle_irq_pmq(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001605{
1606 u32 tmp;
1607
1608 //TODO: AP mode.
1609
1610 while (1) {
1611 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1612 if (!(tmp & 0x00000008))
1613 break;
1614 }
1615 /* 16bit write is odd, but correct. */
1616 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1617}
1618
1619static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1620 u16 ram_offset, u16 shm_size_offset)
1621{
1622 u32 value;
1623 u16 size = 0;
1624
1625 /* Timestamp. */
1626 //FIXME: assumption: The chip sets the timestamp
1627 value = 0;
1628 bcm43xx_ram_write(bcm, ram_offset++, value);
1629 bcm43xx_ram_write(bcm, ram_offset++, value);
1630 size += 8;
1631
1632 /* Beacon Interval / Capability Information */
1633 value = 0x0000;//FIXME: Which interval?
1634 value |= (1 << 0) << 16; /* ESS */
1635 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1636 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1637 if (!bcm->ieee->open_wep)
1638 value |= (1 << 4) << 16; /* Privacy */
1639 bcm43xx_ram_write(bcm, ram_offset++, value);
1640 size += 4;
1641
1642 /* SSID */
1643 //TODO
1644
1645 /* FH Parameter Set */
1646 //TODO
1647
1648 /* DS Parameter Set */
1649 //TODO
1650
1651 /* CF Parameter Set */
1652 //TODO
1653
1654 /* TIM */
1655 //TODO
1656
1657 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1658}
1659
Michael Buesch489423c2006-02-13 00:11:07 +01001660static void handle_irq_beacon(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001661{
1662 u32 status;
1663
1664 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1665 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1666
1667 if ((status & 0x1) && (status & 0x2)) {
1668 /* ACK beacon IRQ. */
1669 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1670 BCM43xx_IRQ_BEACON);
1671 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1672 return;
1673 }
1674 if (!(status & 0x1)) {
1675 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
1676 status |= 0x1;
1677 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1678 }
1679 if (!(status & 0x2)) {
1680 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
1681 status |= 0x2;
1682 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1683 }
1684}
1685
John W. Linvillef2223132006-01-23 16:59:58 -05001686/* Interrupt handler bottom-half */
1687static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
1688{
1689 u32 reason;
1690 u32 dma_reason[4];
1691 int activity = 0;
1692 unsigned long flags;
1693
1694#ifdef CONFIG_BCM43XX_DEBUG
1695 u32 _handled = 0x00000000;
1696# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
1697#else
1698# define bcmirq_handled(irq) do { /* nothing */ } while (0)
1699#endif /* CONFIG_BCM43XX_DEBUG*/
1700
Michael Bueschefccb642006-03-11 13:39:14 +01001701 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001702 reason = bcm->irq_reason;
1703 dma_reason[0] = bcm->dma_reason[0];
1704 dma_reason[1] = bcm->dma_reason[1];
1705 dma_reason[2] = bcm->dma_reason[2];
1706 dma_reason[3] = bcm->dma_reason[3];
1707
1708 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
1709 /* TX error. We get this when Template Ram is written in wrong endianess
1710 * in dummy_tx(). We also get this if something is wrong with the TX header
1711 * on DMA or PIO queues.
1712 * Maybe we get this in other error conditions, too.
1713 */
Michael Buesch73733842006-03-12 19:44:29 +01001714 printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
John W. Linvillef2223132006-01-23 16:59:58 -05001715 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
1716 }
Michael Buesch73733842006-03-12 19:44:29 +01001717 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
1718 (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
1719 (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
1720 (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
1721 printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
1722 "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1723 dma_reason[0], dma_reason[1],
1724 dma_reason[2], dma_reason[3]);
1725 bcm43xx_controller_restart(bcm, "DMA error");
1726 bcm43xx_unlock_mmio(bcm, flags);
1727 return;
1728 }
1729 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
1730 (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
1731 (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
1732 (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
1733 printkl(KERN_ERR PFX "DMA error: "
1734 "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1735 dma_reason[0], dma_reason[1],
1736 dma_reason[2], dma_reason[3]);
1737 }
John W. Linvillef2223132006-01-23 16:59:58 -05001738
1739 if (reason & BCM43xx_IRQ_PS) {
1740 handle_irq_ps(bcm);
1741 bcmirq_handled(BCM43xx_IRQ_PS);
1742 }
1743
1744 if (reason & BCM43xx_IRQ_REG124) {
1745 handle_irq_reg124(bcm);
1746 bcmirq_handled(BCM43xx_IRQ_REG124);
1747 }
1748
1749 if (reason & BCM43xx_IRQ_BEACON) {
1750 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
1751 handle_irq_beacon(bcm);
1752 bcmirq_handled(BCM43xx_IRQ_BEACON);
1753 }
1754
1755 if (reason & BCM43xx_IRQ_PMQ) {
1756 handle_irq_pmq(bcm);
1757 bcmirq_handled(BCM43xx_IRQ_PMQ);
1758 }
1759
1760 if (reason & BCM43xx_IRQ_SCAN) {
1761 /*TODO*/
1762 //bcmirq_handled(BCM43xx_IRQ_SCAN);
1763 }
1764
1765 if (reason & BCM43xx_IRQ_NOISE) {
1766 handle_irq_noise(bcm);
1767 bcmirq_handled(BCM43xx_IRQ_NOISE);
1768 }
1769
1770 /* Check the DMA reason registers for received data. */
1771 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
1772 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
1773 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001774 if (bcm43xx_using_pio(bcm))
Michael Buesche9357c02006-03-13 19:27:34 +01001775 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
John W. Linvillef2223132006-01-23 16:59:58 -05001776 else
Michael Buesche9357c02006-03-13 19:27:34 +01001777 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
Michael Bueschdcfd7202006-02-12 20:25:55 +01001778 /* We intentionally don't set "activity" to 1, here. */
John W. Linvillef2223132006-01-23 16:59:58 -05001779 }
1780 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesche1b1b582006-03-13 15:20:05 +01001781 if (bcm43xx_using_pio(bcm))
Michael Buesche9357c02006-03-13 19:27:34 +01001782 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
Michael Buesche1b1b582006-03-13 15:20:05 +01001783 else
Michael Buesche9357c02006-03-13 19:27:34 +01001784 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
Michael Buesche1b1b582006-03-13 15:20:05 +01001785 activity = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001786 }
1787 bcmirq_handled(BCM43xx_IRQ_RX);
1788
1789 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
Michael Buesche1b1b582006-03-13 15:20:05 +01001790 handle_irq_transmit_status(bcm);
1791 activity = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001792 //TODO: In AP mode, this also causes sending of powersave responses.
1793 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
1794 }
1795
John W. Linvillef2223132006-01-23 16:59:58 -05001796 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
1797 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
1798#ifdef CONFIG_BCM43XX_DEBUG
1799 if (unlikely(reason & ~_handled)) {
1800 printkl(KERN_WARNING PFX
1801 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
1802 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1803 reason, (reason & ~_handled),
1804 dma_reason[0], dma_reason[1],
1805 dma_reason[2], dma_reason[3]);
1806 }
1807#endif
1808#undef bcmirq_handled
1809
1810 if (!modparam_noleds)
1811 bcm43xx_leds_update(bcm, activity);
1812 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
Michael Bueschefccb642006-03-11 13:39:14 +01001813 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001814}
1815
Michael Buesch0ac59da2006-03-19 21:43:40 +01001816static void pio_irq_workaround(struct bcm43xx_private *bcm,
1817 u16 base, int queueidx)
John W. Linvillef2223132006-01-23 16:59:58 -05001818{
Michael Buesch0ac59da2006-03-19 21:43:40 +01001819 u16 rxctl;
John W. Linvillef2223132006-01-23 16:59:58 -05001820
Michael Buesch0ac59da2006-03-19 21:43:40 +01001821 rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);
1822 if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)
1823 bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;
1824 else
1825 bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;
1826}
1827
1828static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
1829{
Michael Buesch77db31e2006-02-12 16:47:44 +01001830 if (bcm43xx_using_pio(bcm) &&
John W. Linvillef2223132006-01-23 16:59:58 -05001831 (bcm->current_core->rev < 3) &&
1832 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
1833 /* Apply a PIO specific workaround to the dma_reasons */
Michael Buesch0ac59da2006-03-19 21:43:40 +01001834 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);
1835 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);
1836 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);
1837 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);
John W. Linvillef2223132006-01-23 16:59:58 -05001838 }
1839
Michael Buesch0ac59da2006-03-19 21:43:40 +01001840 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
John W. Linvillef2223132006-01-23 16:59:58 -05001841
1842 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
1843 bcm->dma_reason[0]);
1844 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
1845 bcm->dma_reason[1]);
1846 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
1847 bcm->dma_reason[2]);
1848 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
1849 bcm->dma_reason[3]);
1850}
1851
1852/* Interrupt handler top-half */
1853static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
1854{
Michael Bueschefccb642006-03-11 13:39:14 +01001855 irqreturn_t ret = IRQ_HANDLED;
John W. Linvillef2223132006-01-23 16:59:58 -05001856 struct bcm43xx_private *bcm = dev_id;
Michael Buesch0ac59da2006-03-19 21:43:40 +01001857 u32 reason;
John W. Linvillef2223132006-01-23 16:59:58 -05001858
1859 if (!bcm)
1860 return IRQ_NONE;
1861
Michael Bueschefccb642006-03-11 13:39:14 +01001862 spin_lock(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001863
1864 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
1865 if (reason == 0xffffffff) {
1866 /* irq not for us (shared irq) */
Michael Bueschefccb642006-03-11 13:39:14 +01001867 ret = IRQ_NONE;
1868 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001869 }
Michael Buesch0ac59da2006-03-19 21:43:40 +01001870 reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
1871 if (!reason)
Michael Bueschefccb642006-03-11 13:39:14 +01001872 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001873
Michael Buesch0ac59da2006-03-19 21:43:40 +01001874 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
1875 & 0x0001dc00;
1876 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
1877 & 0x0000dc00;
1878 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
1879 & 0x0000dc00;
1880 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
1881 & 0x0001dc00;
1882
1883 bcm43xx_interrupt_ack(bcm, reason);
John W. Linvillef2223132006-01-23 16:59:58 -05001884
Michael Bueschbf7b8762006-02-21 17:58:18 +01001885 /* Only accept IRQs, if we are initialized properly.
1886 * This avoids an RX race while initializing.
1887 * We should probably not enable IRQs before we are initialized
1888 * completely, but some careful work is needed to fix this. I think it
1889 * is best to stay with this cheap workaround for now... .
1890 */
1891 if (likely(bcm->initialized)) {
1892 /* disable all IRQs. They are enabled again in the bottom half. */
1893 bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1894 /* save the reason code and call our bottom half. */
1895 bcm->irq_reason = reason;
1896 tasklet_schedule(&bcm->isr_tasklet);
1897 }
John W. Linvillef2223132006-01-23 16:59:58 -05001898
Michael Bueschefccb642006-03-11 13:39:14 +01001899out:
1900 mmiowb();
1901 spin_unlock(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001902
Michael Bueschefccb642006-03-11 13:39:14 +01001903 return ret;
John W. Linvillef2223132006-01-23 16:59:58 -05001904}
1905
Michael Buescha4a600d2006-02-01 22:09:52 +01001906static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
John W. Linvillef2223132006-01-23 16:59:58 -05001907{
Michael Buescha4a600d2006-02-01 22:09:52 +01001908 if (bcm->firmware_norelease && !force)
John W. Linvillef2223132006-01-23 16:59:58 -05001909 return; /* Suspending or controller reset. */
1910 release_firmware(bcm->ucode);
1911 bcm->ucode = NULL;
1912 release_firmware(bcm->pcm);
1913 bcm->pcm = NULL;
1914 release_firmware(bcm->initvals0);
1915 bcm->initvals0 = NULL;
1916 release_firmware(bcm->initvals1);
1917 bcm->initvals1 = NULL;
1918}
1919
1920static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1921{
Michael Buesche9357c02006-03-13 19:27:34 +01001922 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001923 u8 rev = bcm->current_core->rev;
1924 int err = 0;
1925 int nr;
1926 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
1927
1928 if (!bcm->ucode) {
1929 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
1930 (rev >= 5 ? 5 : rev),
1931 modparam_fwpostfix);
1932 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
1933 if (err) {
1934 printk(KERN_ERR PFX
1935 "Error: Microcode \"%s\" not available or load failed.\n",
1936 buf);
1937 goto error;
1938 }
1939 }
1940
1941 if (!bcm->pcm) {
1942 snprintf(buf, ARRAY_SIZE(buf),
1943 "bcm43xx_pcm%d%s.fw",
1944 (rev < 5 ? 4 : 5),
1945 modparam_fwpostfix);
1946 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
1947 if (err) {
1948 printk(KERN_ERR PFX
1949 "Error: PCM \"%s\" not available or load failed.\n",
1950 buf);
1951 goto error;
1952 }
1953 }
1954
1955 if (!bcm->initvals0) {
1956 if (rev == 2 || rev == 4) {
1957 switch (phy->type) {
1958 case BCM43xx_PHYTYPE_A:
1959 nr = 3;
1960 break;
1961 case BCM43xx_PHYTYPE_B:
1962 case BCM43xx_PHYTYPE_G:
1963 nr = 1;
1964 break;
1965 default:
1966 goto err_noinitval;
1967 }
1968
1969 } else if (rev >= 5) {
1970 switch (phy->type) {
1971 case BCM43xx_PHYTYPE_A:
1972 nr = 7;
1973 break;
1974 case BCM43xx_PHYTYPE_B:
1975 case BCM43xx_PHYTYPE_G:
1976 nr = 5;
1977 break;
1978 default:
1979 goto err_noinitval;
1980 }
1981 } else
1982 goto err_noinitval;
1983 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1984 nr, modparam_fwpostfix);
1985
1986 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
1987 if (err) {
1988 printk(KERN_ERR PFX
1989 "Error: InitVals \"%s\" not available or load failed.\n",
1990 buf);
1991 goto error;
1992 }
1993 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
1994 printk(KERN_ERR PFX "InitVals fileformat error.\n");
1995 goto error;
1996 }
1997 }
1998
1999 if (!bcm->initvals1) {
2000 if (rev >= 5) {
2001 u32 sbtmstatehigh;
2002
2003 switch (phy->type) {
2004 case BCM43xx_PHYTYPE_A:
2005 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
2006 if (sbtmstatehigh & 0x00010000)
2007 nr = 9;
2008 else
2009 nr = 10;
2010 break;
2011 case BCM43xx_PHYTYPE_B:
2012 case BCM43xx_PHYTYPE_G:
2013 nr = 6;
2014 break;
2015 default:
2016 goto err_noinitval;
2017 }
2018 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2019 nr, modparam_fwpostfix);
2020
2021 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
2022 if (err) {
2023 printk(KERN_ERR PFX
2024 "Error: InitVals \"%s\" not available or load failed.\n",
2025 buf);
2026 goto error;
2027 }
2028 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
2029 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2030 goto error;
2031 }
2032 }
2033 }
2034
2035out:
2036 return err;
2037error:
Michael Buescha4a600d2006-02-01 22:09:52 +01002038 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002039 goto out;
2040err_noinitval:
2041 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2042 err = -ENOENT;
2043 goto error;
2044}
2045
2046static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2047{
2048 const u32 *data;
2049 unsigned int i, len;
2050
John W. Linvillef2223132006-01-23 16:59:58 -05002051 /* Upload Microcode. */
2052 data = (u32 *)(bcm->ucode->data);
2053 len = bcm->ucode->size / sizeof(u32);
2054 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2055 for (i = 0; i < len; i++) {
2056 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2057 be32_to_cpu(data[i]));
2058 udelay(10);
2059 }
2060
2061 /* Upload PCM data. */
2062 data = (u32 *)(bcm->pcm->data);
2063 len = bcm->pcm->size / sizeof(u32);
2064 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2065 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2066 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2067 for (i = 0; i < len; i++) {
2068 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2069 be32_to_cpu(data[i]));
2070 udelay(10);
2071 }
John W. Linvillef2223132006-01-23 16:59:58 -05002072}
2073
Michael Buescha4a600d2006-02-01 22:09:52 +01002074static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2075 const struct bcm43xx_initval *data,
2076 const unsigned int len)
John W. Linvillef2223132006-01-23 16:59:58 -05002077{
2078 u16 offset, size;
2079 u32 value;
2080 unsigned int i;
2081
2082 for (i = 0; i < len; i++) {
2083 offset = be16_to_cpu(data[i].offset);
2084 size = be16_to_cpu(data[i].size);
2085 value = be32_to_cpu(data[i].value);
2086
Michael Buescha4a600d2006-02-01 22:09:52 +01002087 if (unlikely(offset >= 0x1000))
2088 goto err_format;
2089 if (size == 2) {
2090 if (unlikely(value & 0xFFFF0000))
2091 goto err_format;
2092 bcm43xx_write16(bcm, offset, (u16)value);
2093 } else if (size == 4) {
John W. Linvillef2223132006-01-23 16:59:58 -05002094 bcm43xx_write32(bcm, offset, value);
Michael Buescha4a600d2006-02-01 22:09:52 +01002095 } else
2096 goto err_format;
John W. Linvillef2223132006-01-23 16:59:58 -05002097 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002098
2099 return 0;
2100
2101err_format:
2102 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2103 "Please fix your bcm43xx firmware files.\n");
2104 return -EPROTO;
John W. Linvillef2223132006-01-23 16:59:58 -05002105}
2106
Michael Buescha4a600d2006-02-01 22:09:52 +01002107static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002108{
Michael Buescha4a600d2006-02-01 22:09:52 +01002109 int err;
2110
Michael Buescha4a600d2006-02-01 22:09:52 +01002111 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2112 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2113 if (err)
2114 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002115 if (bcm->initvals1) {
Michael Buescha4a600d2006-02-01 22:09:52 +01002116 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2117 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2118 if (err)
2119 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002120 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002121out:
Michael Buescha4a600d2006-02-01 22:09:52 +01002122 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002123}
2124
2125static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2126{
2127 int res;
2128 unsigned int i;
2129 u32 data;
2130
2131 bcm->irq = bcm->pci_dev->irq;
2132#ifdef CONFIG_BCM947XX
2133 if (bcm->pci_dev->bus->number == 0) {
2134 struct pci_dev *d = NULL;
2135 /* FIXME: we will probably need more device IDs here... */
2136 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2137 if (d != NULL) {
2138 bcm->irq = d->irq;
2139 }
2140 }
2141#endif
2142 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
Michael Buesch65f3f192006-01-31 20:11:38 +01002143 SA_SHIRQ, KBUILD_MODNAME, bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002144 if (res) {
2145 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
Michael Buesch489423c2006-02-13 00:11:07 +01002146 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002147 }
2148 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2149 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2150 i = 0;
2151 while (1) {
2152 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2153 if (data == BCM43xx_IRQ_READY)
2154 break;
2155 i++;
2156 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2157 printk(KERN_ERR PFX "Card IRQ register not responding. "
2158 "Giving up.\n");
2159 free_irq(bcm->irq, bcm);
2160 return -ENODEV;
2161 }
2162 udelay(10);
2163 }
2164 // dummy read
2165 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2166
2167 return 0;
2168}
2169
2170/* Switch to the core used to write the GPIO register.
2171 * This is either the ChipCommon, or the PCI core.
2172 */
Michael Buesch489423c2006-02-13 00:11:07 +01002173static int switch_to_gpio_core(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002174{
2175 int err;
2176
2177 /* Where to find the GPIO register depends on the chipset.
2178 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2179 * control register. Otherwise the register at offset 0x6c in the
2180 * PCI core is the GPIO control register.
2181 */
2182 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2183 if (err == -ENODEV) {
2184 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
Michael Buesch489423c2006-02-13 00:11:07 +01002185 if (unlikely(err == -ENODEV)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002186 printk(KERN_ERR PFX "gpio error: "
2187 "Neither ChipCommon nor PCI core available!\n");
Michael Buesch714eece2006-03-18 21:28:46 +01002188 }
2189 }
John W. Linvillef2223132006-01-23 16:59:58 -05002190
Michael Buesch714eece2006-03-18 21:28:46 +01002191 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002192}
2193
2194/* Initialize the GPIOs
2195 * http://bcm-specs.sipsolutions.net/GPIO
2196 */
2197static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2198{
2199 struct bcm43xx_coreinfo *old_core;
2200 int err;
Michael Buesch714eece2006-03-18 21:28:46 +01002201 u32 mask, set;
John W. Linvillef2223132006-01-23 16:59:58 -05002202
Michael Buesch714eece2006-03-18 21:28:46 +01002203 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2204 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2205 & 0xFFFF3FFF);
John W. Linvillef2223132006-01-23 16:59:58 -05002206
Michael Buesch714eece2006-03-18 21:28:46 +01002207 bcm43xx_leds_switch_all(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002208 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2209 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2210
Michael Buesch714eece2006-03-18 21:28:46 +01002211 mask = 0x0000001F;
2212 set = 0x0000000F;
John W. Linvillef2223132006-01-23 16:59:58 -05002213 if (bcm->chip_id == 0x4301) {
Michael Buesch714eece2006-03-18 21:28:46 +01002214 mask |= 0x0060;
2215 set |= 0x0060;
2216 }
2217 if (0 /* FIXME: conditional unknown */) {
2218 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2219 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2220 | 0x0100);
2221 mask |= 0x0180;
2222 set |= 0x0180;
John W. Linvillef2223132006-01-23 16:59:58 -05002223 }
2224 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
Michael Buesch714eece2006-03-18 21:28:46 +01002225 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2226 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2227 | 0x0200);
2228 mask |= 0x0200;
2229 set |= 0x0200;
John W. Linvillef2223132006-01-23 16:59:58 -05002230 }
Michael Buesch714eece2006-03-18 21:28:46 +01002231 if (bcm->current_core->rev >= 2)
2232 mask |= 0x0010; /* FIXME: This is redundant. */
John W. Linvillef2223132006-01-23 16:59:58 -05002233
Michael Buesch714eece2006-03-18 21:28:46 +01002234 old_core = bcm->current_core;
2235 err = switch_to_gpio_core(bcm);
2236 if (err)
2237 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002238 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
Michael Buesch714eece2006-03-18 21:28:46 +01002239 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);
John W. Linvillef2223132006-01-23 16:59:58 -05002240 err = bcm43xx_switch_core(bcm, old_core);
Michael Buesch714eece2006-03-18 21:28:46 +01002241out:
2242 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002243}
2244
2245/* Turn off all GPIO stuff. Call this on module unload, for example. */
2246static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2247{
2248 struct bcm43xx_coreinfo *old_core;
2249 int err;
2250
2251 old_core = bcm->current_core;
2252 err = switch_to_gpio_core(bcm);
2253 if (err)
2254 return err;
2255 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2256 err = bcm43xx_switch_core(bcm, old_core);
2257 assert(err == 0);
2258
2259 return 0;
2260}
2261
2262/* http://bcm-specs.sipsolutions.net/EnableMac */
2263void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2264{
2265 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2266 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2267 | BCM43xx_SBF_MAC_ENABLED);
2268 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2269 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2270 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2271 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2272}
2273
2274/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2275void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2276{
2277 int i;
2278 u32 tmp;
2279
2280 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2281 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2282 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2283 & ~BCM43xx_SBF_MAC_ENABLED);
2284 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
Michael Buesch921e4852006-02-08 17:55:55 +01002285 for (i = 100000; i; i--) {
John W. Linvillef2223132006-01-23 16:59:58 -05002286 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch921e4852006-02-08 17:55:55 +01002287 if (tmp & BCM43xx_IRQ_READY)
2288 return;
John W. Linvillef2223132006-01-23 16:59:58 -05002289 udelay(10);
2290 }
Michael Buesch921e4852006-02-08 17:55:55 +01002291 printkl(KERN_ERR PFX "MAC suspend failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05002292}
2293
2294void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2295 int iw_mode)
2296{
2297 unsigned long flags;
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002298 struct net_device *net_dev = bcm->net_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05002299 u32 status;
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002300 u16 value;
John W. Linvillef2223132006-01-23 16:59:58 -05002301
2302 spin_lock_irqsave(&bcm->ieee->lock, flags);
2303 bcm->ieee->iw_mode = iw_mode;
2304 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2305 if (iw_mode == IW_MODE_MONITOR)
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002306 net_dev->type = ARPHRD_IEEE80211;
John W. Linvillef2223132006-01-23 16:59:58 -05002307 else
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002308 net_dev->type = ARPHRD_ETHER;
John W. Linvillef2223132006-01-23 16:59:58 -05002309
John W. Linvillef2223132006-01-23 16:59:58 -05002310 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2311 /* Reset status to infrastructured mode */
2312 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002313 status &= ~BCM43xx_SBF_MODE_PROMISC;
2314 status |= BCM43xx_SBF_MODE_NOTADHOC;
2315
2316/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */
2317status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002318
2319 switch (iw_mode) {
2320 case IW_MODE_MONITOR:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002321 status |= BCM43xx_SBF_MODE_MONITOR;
2322 status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002323 break;
2324 case IW_MODE_ADHOC:
2325 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2326 break;
2327 case IW_MODE_MASTER:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002328 status |= BCM43xx_SBF_MODE_AP;
2329 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002330 case IW_MODE_SECOND:
2331 case IW_MODE_REPEAT:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002332 TODO(); /* TODO */
John W. Linvillef2223132006-01-23 16:59:58 -05002333 break;
2334 case IW_MODE_INFRA:
2335 /* nothing to be done here... */
2336 break;
2337 default:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002338 dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);
John W. Linvillef2223132006-01-23 16:59:58 -05002339 }
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002340 if (net_dev->flags & IFF_PROMISC)
2341 status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002342 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002343
2344 value = 0x0002;
2345 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2346 if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
2347 value = 0x0064;
2348 else
2349 value = 0x0032;
2350 }
2351 bcm43xx_write16(bcm, 0x0612, value);
John W. Linvillef2223132006-01-23 16:59:58 -05002352}
2353
2354/* This is the opposite of bcm43xx_chip_init() */
2355static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2356{
2357 bcm43xx_radio_turn_off(bcm);
2358 if (!modparam_noleds)
2359 bcm43xx_leds_exit(bcm);
2360 bcm43xx_gpio_cleanup(bcm);
2361 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002362 bcm43xx_release_firmware(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002363}
2364
2365/* Initialize the chip
2366 * http://bcm-specs.sipsolutions.net/ChipInit
2367 */
2368static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2369{
Michael Buesche9357c02006-03-13 19:27:34 +01002370 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
2371 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002372 int err;
John W. Linvillef2223132006-01-23 16:59:58 -05002373 int tmp;
2374 u32 value32;
2375 u16 value16;
2376
2377 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2378 BCM43xx_SBF_CORE_READY
2379 | BCM43xx_SBF_400);
2380
2381 err = bcm43xx_request_firmware(bcm);
2382 if (err)
2383 goto out;
2384 bcm43xx_upload_microcode(bcm);
2385
2386 err = bcm43xx_initialize_irq(bcm);
2387 if (err)
Michael Buescha4a600d2006-02-01 22:09:52 +01002388 goto err_release_fw;
John W. Linvillef2223132006-01-23 16:59:58 -05002389
2390 err = bcm43xx_gpio_init(bcm);
2391 if (err)
2392 goto err_free_irq;
2393
Michael Buescha4a600d2006-02-01 22:09:52 +01002394 err = bcm43xx_upload_initvals(bcm);
2395 if (err)
2396 goto err_gpio_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002397 bcm43xx_radio_turn_on(bcm);
2398
John W. Linvillef2223132006-01-23 16:59:58 -05002399 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2400 err = bcm43xx_phy_init(bcm);
2401 if (err)
2402 goto err_radio_off;
2403
2404 /* Select initial Interference Mitigation. */
Michael Buesche9357c02006-03-13 19:27:34 +01002405 tmp = radio->interfmode;
2406 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
John W. Linvillef2223132006-01-23 16:59:58 -05002407 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2408
2409 bcm43xx_phy_set_antenna_diversity(bcm);
2410 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
Michael Buesche9357c02006-03-13 19:27:34 +01002411 if (phy->type == BCM43xx_PHYTYPE_B) {
John W. Linvillef2223132006-01-23 16:59:58 -05002412 value16 = bcm43xx_read16(bcm, 0x005E);
2413 value16 |= 0x0004;
2414 bcm43xx_write16(bcm, 0x005E, value16);
2415 }
2416 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2417 if (bcm->current_core->rev < 5)
2418 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2419
2420 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2421 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2422 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2423 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2424 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2425 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
John W. Linvillef2223132006-01-23 16:59:58 -05002426
John W. Linvillef2223132006-01-23 16:59:58 -05002427 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002428 value32 |= 0x100000;
John W. Linvillef2223132006-01-23 16:59:58 -05002429 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2430
Michael Buesch77db31e2006-02-12 16:47:44 +01002431 if (bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002432 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2433 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2434 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2435 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2436 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2437 }
2438
2439 /* Probe Response Timeout value */
2440 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2441 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2442
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002443 /* Initially set the wireless operation mode. */
2444 bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode);
John W. Linvillef2223132006-01-23 16:59:58 -05002445
2446 if (bcm->current_core->rev < 3) {
2447 bcm43xx_write16(bcm, 0x060E, 0x0000);
2448 bcm43xx_write16(bcm, 0x0610, 0x8000);
2449 bcm43xx_write16(bcm, 0x0604, 0x0000);
2450 bcm43xx_write16(bcm, 0x0606, 0x0200);
2451 } else {
2452 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2453 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2454 }
2455 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2456 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2457 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2458 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2459 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2460
2461 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2462 value32 |= 0x00100000;
2463 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2464
2465 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2466
2467 assert(err == 0);
2468 dprintk(KERN_INFO PFX "Chip initialized\n");
2469out:
2470 return err;
2471
2472err_radio_off:
2473 bcm43xx_radio_turn_off(bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002474err_gpio_cleanup:
John W. Linvillef2223132006-01-23 16:59:58 -05002475 bcm43xx_gpio_cleanup(bcm);
2476err_free_irq:
2477 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002478err_release_fw:
2479 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002480 goto out;
2481}
2482
2483/* Validate chip access
2484 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2485static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2486{
John W. Linvillef2223132006-01-23 16:59:58 -05002487 u32 value;
2488 u32 shm_backup;
2489
2490 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2491 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
Michael Buesch489423c2006-02-13 00:11:07 +01002492 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2493 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002494 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
Michael Buesch489423c2006-02-13 00:11:07 +01002495 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2496 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002497 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2498
2499 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch489423c2006-02-13 00:11:07 +01002500 if ((value | 0x80000000) != 0x80000400)
2501 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002502
2503 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch489423c2006-02-13 00:11:07 +01002504 if (value != 0x00000000)
2505 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002506
Michael Buesch489423c2006-02-13 00:11:07 +01002507 return 0;
2508error:
2509 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2510 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002511}
2512
Michael Buesch8afceb12006-03-25 17:04:41 +01002513static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
Michael Buesche9357c02006-03-13 19:27:34 +01002514{
2515 /* Initialize a "phyinfo" structure. The structure is already
2516 * zeroed out.
2517 */
2518 phy->antenna_diversity = 0xFFFF;
2519 phy->savedpctlreg = 0xFFFF;
2520 phy->minlowsig[0] = 0xFFFF;
2521 phy->minlowsig[1] = 0xFFFF;
2522 spin_lock_init(&phy->lock);
2523}
2524
Michael Buesch8afceb12006-03-25 17:04:41 +01002525static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
Michael Buesche9357c02006-03-13 19:27:34 +01002526{
2527 /* Initialize a "radioinfo" structure. The structure is already
2528 * zeroed out.
2529 */
2530 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2531 radio->channel = 0xFF;
2532 radio->initial_channel = 0xFF;
2533 radio->lofcal = 0xFFFF;
2534 radio->initval = 0xFFFF;
2535 radio->nrssi[0] = -1000;
2536 radio->nrssi[1] = -1000;
2537}
2538
John W. Linvillef2223132006-01-23 16:59:58 -05002539static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2540{
2541 int err, i;
2542 int current_core;
2543 u32 core_vendor, core_id, core_rev;
2544 u32 sb_id_hi, chip_id_32 = 0;
2545 u16 pci_device, chip_id_16;
2546 u8 core_count;
2547
2548 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2549 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
John W. Linvillef2223132006-01-23 16:59:58 -05002550 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2551 * BCM43xx_MAX_80211_CORES);
Michael Buesche9357c02006-03-13 19:27:34 +01002552 memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
2553 * BCM43xx_MAX_80211_CORES);
2554 bcm->current_80211_core_idx = -1;
2555 bcm->nr_80211_available = 0;
2556 bcm->current_core = NULL;
2557 bcm->active_80211_core = NULL;
John W. Linvillef2223132006-01-23 16:59:58 -05002558
2559 /* map core 0 */
2560 err = _switch_core(bcm, 0);
2561 if (err)
2562 goto out;
2563
2564 /* fetch sb_id_hi from core information registers */
2565 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2566
2567 core_id = (sb_id_hi & 0xFFF0) >> 4;
2568 core_rev = (sb_id_hi & 0xF);
2569 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2570
2571 /* if present, chipcommon is always core 0; read the chipid from it */
2572 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2573 chip_id_32 = bcm43xx_read32(bcm, 0);
2574 chip_id_16 = chip_id_32 & 0xFFFF;
Michael Buesche9357c02006-03-13 19:27:34 +01002575 bcm->core_chipcommon.available = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002576 bcm->core_chipcommon.id = core_id;
2577 bcm->core_chipcommon.rev = core_rev;
2578 bcm->core_chipcommon.index = 0;
2579 /* While we are at it, also read the capabilities. */
2580 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2581 } else {
2582 /* without a chipCommon, use a hard coded table. */
2583 pci_device = bcm->pci_dev->device;
2584 if (pci_device == 0x4301)
2585 chip_id_16 = 0x4301;
2586 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2587 chip_id_16 = 0x4307;
2588 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2589 chip_id_16 = 0x4402;
2590 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2591 chip_id_16 = 0x4610;
2592 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2593 chip_id_16 = 0x4710;
2594#ifdef CONFIG_BCM947XX
2595 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2596 chip_id_16 = 0x4309;
2597#endif
2598 else {
2599 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2600 return -ENODEV;
2601 }
2602 }
2603
2604 /* ChipCommon with Core Rev >=4 encodes number of cores,
2605 * otherwise consult hardcoded table */
2606 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2607 core_count = (chip_id_32 & 0x0F000000) >> 24;
2608 } else {
2609 switch (chip_id_16) {
2610 case 0x4610:
2611 case 0x4704:
2612 case 0x4710:
2613 core_count = 9;
2614 break;
2615 case 0x4310:
2616 core_count = 8;
2617 break;
2618 case 0x5365:
2619 core_count = 7;
2620 break;
2621 case 0x4306:
2622 core_count = 6;
2623 break;
2624 case 0x4301:
2625 case 0x4307:
2626 core_count = 5;
2627 break;
2628 case 0x4402:
2629 core_count = 3;
2630 break;
2631 default:
2632 /* SOL if we get here */
2633 assert(0);
2634 core_count = 1;
2635 }
2636 }
2637
2638 bcm->chip_id = chip_id_16;
Michael Bueschadc40e92006-03-25 20:36:57 +01002639 bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16;
2640 bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20;
John W. Linvillef2223132006-01-23 16:59:58 -05002641
2642 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2643 bcm->chip_id, bcm->chip_rev);
2644 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
Michael Buesche9357c02006-03-13 19:27:34 +01002645 if (bcm->core_chipcommon.available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002646 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2647 core_id, core_rev, core_vendor,
2648 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2649 }
2650
Michael Buesche9357c02006-03-13 19:27:34 +01002651 if (bcm->core_chipcommon.available)
John W. Linvillef2223132006-01-23 16:59:58 -05002652 current_core = 1;
2653 else
2654 current_core = 0;
2655 for ( ; current_core < core_count; current_core++) {
2656 struct bcm43xx_coreinfo *core;
Michael Buesche9357c02006-03-13 19:27:34 +01002657 struct bcm43xx_coreinfo_80211 *ext_80211;
John W. Linvillef2223132006-01-23 16:59:58 -05002658
2659 err = _switch_core(bcm, current_core);
2660 if (err)
2661 goto out;
2662 /* Gather information */
2663 /* fetch sb_id_hi from core information registers */
2664 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2665
2666 /* extract core_id, core_rev, core_vendor */
2667 core_id = (sb_id_hi & 0xFFF0) >> 4;
2668 core_rev = (sb_id_hi & 0xF);
2669 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2670
2671 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2672 current_core, core_id, core_rev, core_vendor,
2673 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2674
2675 core = NULL;
2676 switch (core_id) {
2677 case BCM43xx_COREID_PCI:
2678 core = &bcm->core_pci;
Michael Buesche9357c02006-03-13 19:27:34 +01002679 if (core->available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002680 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2681 continue;
2682 }
2683 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002684 case BCM43xx_COREID_80211:
2685 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2686 core = &(bcm->core_80211[i]);
Michael Buesche9357c02006-03-13 19:27:34 +01002687 ext_80211 = &(bcm->core_80211_ext[i]);
2688 if (!core->available)
John W. Linvillef2223132006-01-23 16:59:58 -05002689 break;
2690 core = NULL;
2691 }
2692 if (!core) {
2693 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2694 BCM43xx_MAX_80211_CORES);
2695 continue;
2696 }
2697 if (i != 0) {
2698 /* More than one 80211 core is only supported
2699 * by special chips.
2700 * There are chips with two 80211 cores, but with
2701 * dangling pins on the second core. Be careful
2702 * and ignore these cores here.
2703 */
2704 if (bcm->pci_dev->device != 0x4324) {
2705 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2706 continue;
2707 }
2708 }
2709 switch (core_rev) {
2710 case 2:
2711 case 4:
2712 case 5:
2713 case 6:
2714 case 7:
2715 case 9:
2716 break;
2717 default:
2718 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2719 core_rev);
2720 err = -ENODEV;
2721 goto out;
2722 }
Michael Buesche9357c02006-03-13 19:27:34 +01002723 bcm->nr_80211_available++;
2724 bcm43xx_init_struct_phyinfo(&ext_80211->phy);
2725 bcm43xx_init_struct_radioinfo(&ext_80211->radio);
John W. Linvillef2223132006-01-23 16:59:58 -05002726 break;
2727 case BCM43xx_COREID_CHIPCOMMON:
2728 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2729 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002730 }
2731 if (core) {
Michael Buesche9357c02006-03-13 19:27:34 +01002732 core->available = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002733 core->id = core_id;
2734 core->rev = core_rev;
2735 core->index = current_core;
2736 }
2737 }
2738
Michael Buesche9357c02006-03-13 19:27:34 +01002739 if (!bcm->core_80211[0].available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002740 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2741 err = -ENODEV;
2742 goto out;
2743 }
2744
2745 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2746
2747 assert(err == 0);
2748out:
2749 return err;
2750}
2751
2752static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2753{
2754 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2755 u8 *bssid = bcm->ieee->bssid;
2756
2757 switch (bcm->ieee->iw_mode) {
2758 case IW_MODE_ADHOC:
2759 random_ether_addr(bssid);
2760 break;
2761 case IW_MODE_MASTER:
2762 case IW_MODE_INFRA:
2763 case IW_MODE_REPEAT:
2764 case IW_MODE_SECOND:
2765 case IW_MODE_MONITOR:
2766 memcpy(bssid, mac, ETH_ALEN);
2767 break;
2768 default:
2769 assert(0);
2770 }
2771}
2772
2773static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
2774 u16 rate,
2775 int is_ofdm)
2776{
2777 u16 offset;
2778
2779 if (is_ofdm) {
2780 offset = 0x480;
2781 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2782 }
2783 else {
2784 offset = 0x4C0;
2785 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2786 }
2787 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
2788 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
2789}
2790
2791static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
2792{
Michael Buesche9357c02006-03-13 19:27:34 +01002793 switch (bcm43xx_current_phy(bcm)->type) {
John W. Linvillef2223132006-01-23 16:59:58 -05002794 case BCM43xx_PHYTYPE_A:
2795 case BCM43xx_PHYTYPE_G:
2796 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
2797 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
2798 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
2799 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
2800 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
2801 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
2802 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
2803 case BCM43xx_PHYTYPE_B:
2804 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
2805 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
2806 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
2807 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
2808 break;
2809 default:
2810 assert(0);
2811 }
2812}
2813
2814static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2815{
2816 bcm43xx_chip_cleanup(bcm);
2817 bcm43xx_pio_free(bcm);
2818 bcm43xx_dma_free(bcm);
2819
Michael Buesche9357c02006-03-13 19:27:34 +01002820 bcm->current_core->initialized = 0;
John W. Linvillef2223132006-01-23 16:59:58 -05002821}
2822
2823/* http://bcm-specs.sipsolutions.net/80211Init */
2824static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2825{
Michael Buesche9357c02006-03-13 19:27:34 +01002826 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2827 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002828 u32 ucodeflags;
2829 int err;
2830 u32 sbimconfiglow;
2831 u8 limit;
2832
2833 if (bcm->chip_rev < 5) {
2834 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
2835 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
2836 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
2837 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
2838 sbimconfiglow |= 0x32;
2839 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
2840 sbimconfiglow |= 0x53;
2841 else
2842 assert(0);
2843 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
2844 }
2845
2846 bcm43xx_phy_calibrate(bcm);
2847 err = bcm43xx_chip_init(bcm);
2848 if (err)
2849 goto out;
2850
2851 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
2852 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
2853
2854 if (0 /*FIXME: which condition has to be used here? */)
2855 ucodeflags |= 0x00000010;
2856
2857 /* HW decryption needs to be set now */
2858 ucodeflags |= 0x40000000;
2859
Michael Buesche9357c02006-03-13 19:27:34 +01002860 if (phy->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -05002861 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
Michael Buesche9357c02006-03-13 19:27:34 +01002862 if (phy->rev == 1)
John W. Linvillef2223132006-01-23 16:59:58 -05002863 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
2864 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
2865 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
Michael Buesche9357c02006-03-13 19:27:34 +01002866 } else if (phy->type == BCM43xx_PHYTYPE_B) {
John W. Linvillef2223132006-01-23 16:59:58 -05002867 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
Michael Buesche9357c02006-03-13 19:27:34 +01002868 if (phy->rev >= 2 && radio->version == 0x2050)
John W. Linvillef2223132006-01-23 16:59:58 -05002869 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
2870 }
2871
2872 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2873 BCM43xx_UCODEFLAGS_OFFSET)) {
2874 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2875 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
2876 }
2877
2878 /* Short/Long Retry Limit.
2879 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
2880 * the chip-internal counter.
2881 */
2882 limit = limit_value(modparam_short_retry, 0, 0xF);
2883 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
2884 limit = limit_value(modparam_long_retry, 0, 0xF);
2885 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
2886
2887 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
2888 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
2889
2890 bcm43xx_rate_memory_init(bcm);
2891
2892 /* Minimum Contention Window */
Michael Buesche9357c02006-03-13 19:27:34 +01002893 if (phy->type == BCM43xx_PHYTYPE_B)
John W. Linvillef2223132006-01-23 16:59:58 -05002894 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
2895 else
2896 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
2897 /* Maximum Contention Window */
2898 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
2899
2900 bcm43xx_gen_bssid(bcm);
2901 bcm43xx_write_mac_bssid_templates(bcm);
2902
2903 if (bcm->current_core->rev >= 5)
2904 bcm43xx_write16(bcm, 0x043C, 0x000C);
2905
Michael Buesch77db31e2006-02-12 16:47:44 +01002906 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05002907 err = bcm43xx_pio_init(bcm);
Michael Buesch77db31e2006-02-12 16:47:44 +01002908 else
2909 err = bcm43xx_dma_init(bcm);
2910 if (err)
2911 goto err_chip_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002912 bcm43xx_write16(bcm, 0x0612, 0x0050);
2913 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2914 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2915
2916 bcm43xx_mac_enable(bcm);
2917 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2918
Michael Buesche9357c02006-03-13 19:27:34 +01002919 bcm->current_core->initialized = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002920out:
2921 return err;
2922
2923err_chip_cleanup:
2924 bcm43xx_chip_cleanup(bcm);
2925 goto out;
2926}
2927
2928static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
2929{
2930 int err;
2931 u16 pci_status;
2932
2933 err = bcm43xx_pctl_set_crystal(bcm, 1);
2934 if (err)
2935 goto out;
2936 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
2937 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
2938
2939out:
2940 return err;
2941}
2942
2943static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
2944{
2945 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
2946 bcm43xx_pctl_set_crystal(bcm, 0);
2947}
2948
Michael Buesch489423c2006-02-13 00:11:07 +01002949static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
2950 u32 address,
2951 u32 data)
John W. Linvillef2223132006-01-23 16:59:58 -05002952{
2953 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
2954 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
2955}
2956
2957static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
2958{
2959 int err;
2960 struct bcm43xx_coreinfo *old_core;
2961
2962 old_core = bcm->current_core;
2963 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2964 if (err)
2965 goto out;
2966
2967 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
2968
2969 bcm43xx_switch_core(bcm, old_core);
2970 assert(err == 0);
2971out:
2972 return err;
2973}
2974
2975/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
2976 * To enable core 0, pass a core_mask of 1<<0
2977 */
2978static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
2979 u32 core_mask)
2980{
2981 u32 backplane_flag_nr;
2982 u32 value;
2983 struct bcm43xx_coreinfo *old_core;
2984 int err = 0;
2985
2986 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
2987 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
2988
2989 old_core = bcm->current_core;
2990 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2991 if (err)
2992 goto out;
2993
2994 if (bcm->core_pci.rev < 6) {
2995 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
2996 value |= (1 << backplane_flag_nr);
2997 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
2998 } else {
2999 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
3000 if (err) {
3001 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3002 goto out_switch_back;
3003 }
3004 value |= core_mask << 8;
3005 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3006 if (err) {
3007 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3008 goto out_switch_back;
3009 }
3010 }
3011
3012 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3013 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3014 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3015
3016 if (bcm->core_pci.rev < 5) {
3017 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3018 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3019 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3020 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3021 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3022 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3023 err = bcm43xx_pcicore_commit_settings(bcm);
3024 assert(err == 0);
3025 }
3026
3027out_switch_back:
3028 err = bcm43xx_switch_core(bcm, old_core);
3029out:
3030 return err;
3031}
3032
3033static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3034{
3035 ieee80211softmac_start(bcm->net_dev);
3036}
3037
Michael Bueschab4977f2006-02-12 22:40:39 +01003038static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003039{
Michael Buesche9357c02006-03-13 19:27:34 +01003040 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003041
Michael Bueschab4977f2006-02-12 22:40:39 +01003042 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3043 return;
John W. Linvillef2223132006-01-23 16:59:58 -05003044
Michael Bueschab4977f2006-02-12 22:40:39 +01003045 bcm43xx_mac_suspend(bcm);
3046 bcm43xx_phy_lo_g_measure(bcm);
3047 bcm43xx_mac_enable(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003048}
3049
Michael Bueschab4977f2006-02-12 22:40:39 +01003050static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003051{
John W. Linvillef2223132006-01-23 16:59:58 -05003052 bcm43xx_phy_lo_mark_all_unused(bcm);
3053 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3054 bcm43xx_mac_suspend(bcm);
3055 bcm43xx_calc_nrssi_slope(bcm);
3056 bcm43xx_mac_enable(bcm);
3057 }
John W. Linvillef2223132006-01-23 16:59:58 -05003058}
3059
Michael Bueschab4977f2006-02-12 22:40:39 +01003060static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003061{
John W. Linvillef2223132006-01-23 16:59:58 -05003062 /* Update device statistics. */
3063 bcm43xx_calculate_link_quality(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003064}
John W. Linvillef2223132006-01-23 16:59:58 -05003065
Michael Bueschab4977f2006-02-12 22:40:39 +01003066static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3067{
Michael Buesche9357c02006-03-13 19:27:34 +01003068 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
3069 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003070
3071 if (phy->type == BCM43xx_PHYTYPE_G) {
3072 //TODO: update_aci_moving_average
3073 if (radio->aci_enable && radio->aci_wlan_automatic) {
3074 bcm43xx_mac_suspend(bcm);
3075 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3076 if (0 /*TODO: bunch of conditions*/) {
3077 bcm43xx_radio_set_interference_mitigation(bcm,
3078 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3079 }
3080 } else if (1/*TODO*/) {
3081 /*
3082 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3083 bcm43xx_radio_set_interference_mitigation(bcm,
3084 BCM43xx_RADIO_INTERFMODE_NONE);
3085 }
3086 */
3087 }
3088 bcm43xx_mac_enable(bcm);
3089 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3090 phy->rev == 1) {
3091 //TODO: implement rev1 workaround
3092 }
John W. Linvillef2223132006-01-23 16:59:58 -05003093 }
Michael Bueschab4977f2006-02-12 22:40:39 +01003094 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3095 //TODO for APHY (temperature?)
3096}
3097
3098static void bcm43xx_periodic_task_handler(unsigned long d)
3099{
3100 struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
3101 unsigned long flags;
3102 unsigned int state;
3103
Michael Bueschefccb642006-03-11 13:39:14 +01003104 bcm43xx_lock_mmio(bcm, flags);
Michael Bueschab4977f2006-02-12 22:40:39 +01003105
3106 assert(bcm->initialized);
3107 state = bcm->periodic_state;
3108 if (state % 8 == 0)
3109 bcm43xx_periodic_every120sec(bcm);
3110 if (state % 4 == 0)
3111 bcm43xx_periodic_every60sec(bcm);
3112 if (state % 2 == 0)
3113 bcm43xx_periodic_every30sec(bcm);
3114 bcm43xx_periodic_every15sec(bcm);
3115 bcm->periodic_state = state + 1;
3116
3117 mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
3118
Michael Bueschefccb642006-03-11 13:39:14 +01003119 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003120}
3121
John W. Linvillef2223132006-01-23 16:59:58 -05003122static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3123{
Michael Bueschab4977f2006-02-12 22:40:39 +01003124 del_timer_sync(&bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003125}
3126
John W. Linvillef2223132006-01-23 16:59:58 -05003127static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3128{
Michael Bueschab4977f2006-02-12 22:40:39 +01003129 struct timer_list *timer = &(bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003130
Michael Buesch1d1a73c2006-02-21 18:19:59 +01003131 assert(bcm->initialized);
Michael Bueschab4977f2006-02-12 22:40:39 +01003132 setup_timer(timer,
3133 bcm43xx_periodic_task_handler,
3134 (unsigned long)bcm);
3135 timer->expires = jiffies;
3136 add_timer(timer);
John W. Linvillef2223132006-01-23 16:59:58 -05003137}
3138
3139static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3140{
3141 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3142 0x0056) * 2;
3143 bcm43xx_clear_keys(bcm);
3144}
3145
3146/* This is the opposite of bcm43xx_init_board() */
3147static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3148{
3149 int i, err;
3150 unsigned long flags;
3151
Michael Buesch367f8992006-02-28 15:32:19 +01003152 bcm43xx_sysfs_unregister(bcm);
3153
Michael Bueschab4977f2006-02-12 22:40:39 +01003154 bcm43xx_periodic_tasks_delete(bcm);
3155
Michael Bueschefccb642006-03-11 13:39:14 +01003156 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003157 bcm->initialized = 0;
3158 bcm->shutting_down = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003159 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003160
John W. Linvillef2223132006-01-23 16:59:58 -05003161 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003162 if (!bcm->core_80211[i].available)
John W. Linvillef2223132006-01-23 16:59:58 -05003163 continue;
Michael Buesche9357c02006-03-13 19:27:34 +01003164 if (!bcm->core_80211[i].initialized)
John W. Linvillef2223132006-01-23 16:59:58 -05003165 continue;
3166
3167 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3168 assert(err == 0);
3169 bcm43xx_wireless_core_cleanup(bcm);
3170 }
3171
3172 bcm43xx_pctl_set_crystal(bcm, 0);
3173
Michael Bueschefccb642006-03-11 13:39:14 +01003174 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003175 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003176 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003177}
3178
3179static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3180{
3181 int i, err;
John W. Linvillef2223132006-01-23 16:59:58 -05003182 int connect_phy;
3183 unsigned long flags;
3184
3185 might_sleep();
3186
Michael Bueschefccb642006-03-11 13:39:14 +01003187 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003188 bcm->initialized = 0;
3189 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003190 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003191
3192 err = bcm43xx_pctl_set_crystal(bcm, 1);
3193 if (err)
3194 goto out;
3195 err = bcm43xx_pctl_init(bcm);
3196 if (err)
3197 goto err_crystal_off;
3198 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3199 if (err)
3200 goto err_crystal_off;
3201
3202 tasklet_enable(&bcm->isr_tasklet);
Michael Buesche9357c02006-03-13 19:27:34 +01003203 for (i = 0; i < bcm->nr_80211_available; i++) {
John W. Linvillef2223132006-01-23 16:59:58 -05003204 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3205 assert(err != -ENODEV);
3206 if (err)
3207 goto err_80211_unwind;
3208
3209 /* Enable the selected wireless core.
3210 * Connect PHY only on the first core.
3211 */
3212 if (!bcm43xx_core_enabled(bcm)) {
Michael Buesche9357c02006-03-13 19:27:34 +01003213 if (bcm->nr_80211_available == 1) {
3214 connect_phy = bcm43xx_current_phy(bcm)->connected;
John W. Linvillef2223132006-01-23 16:59:58 -05003215 } else {
3216 if (i == 0)
3217 connect_phy = 1;
3218 else
3219 connect_phy = 0;
3220 }
3221 bcm43xx_wireless_core_reset(bcm, connect_phy);
3222 }
3223
3224 if (i != 0)
3225 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3226
3227 err = bcm43xx_wireless_core_init(bcm);
3228 if (err)
3229 goto err_80211_unwind;
3230
3231 if (i != 0) {
3232 bcm43xx_mac_suspend(bcm);
3233 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3234 bcm43xx_radio_turn_off(bcm);
3235 }
3236 }
3237 bcm->active_80211_core = &bcm->core_80211[0];
Michael Buesche9357c02006-03-13 19:27:34 +01003238 if (bcm->nr_80211_available >= 2) {
John W. Linvillef2223132006-01-23 16:59:58 -05003239 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3240 bcm43xx_mac_enable(bcm);
3241 }
3242 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3243 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3244 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3245 bcm43xx_security_init(bcm);
3246 bcm43xx_softmac_init(bcm);
3247
3248 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3249
Michael Buesche9357c02006-03-13 19:27:34 +01003250 if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
John W. Linvillef2223132006-01-23 16:59:58 -05003251 bcm43xx_mac_suspend(bcm);
Michael Buesche9357c02006-03-13 19:27:34 +01003252 bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05003253 bcm43xx_mac_enable(bcm);
3254 }
Michael Bueschcad2b312006-02-21 18:08:55 +01003255
3256 /* Initialization of the board is done. Flag it as such. */
Michael Bueschefccb642006-03-11 13:39:14 +01003257 bcm43xx_lock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003258 bcm->initialized = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003259 bcm43xx_unlock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003260
John W. Linvillef2223132006-01-23 16:59:58 -05003261 bcm43xx_periodic_tasks_setup(bcm);
Michael Buesch367f8992006-02-28 15:32:19 +01003262 bcm43xx_sysfs_register(bcm);
3263 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
John W. Linvillef2223132006-01-23 16:59:58 -05003264
3265 assert(err == 0);
3266out:
3267 return err;
3268
3269err_80211_unwind:
3270 tasklet_disable(&bcm->isr_tasklet);
3271 /* unwind all 80211 initialization */
Michael Buesche9357c02006-03-13 19:27:34 +01003272 for (i = 0; i < bcm->nr_80211_available; i++) {
3273 if (!bcm->core_80211[i].initialized)
John W. Linvillef2223132006-01-23 16:59:58 -05003274 continue;
3275 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3276 bcm43xx_wireless_core_cleanup(bcm);
3277 }
3278err_crystal_off:
3279 bcm43xx_pctl_set_crystal(bcm, 0);
3280 goto out;
3281}
3282
3283static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3284{
3285 struct pci_dev *pci_dev = bcm->pci_dev;
3286 int i;
3287
3288 bcm43xx_chipset_detach(bcm);
3289 /* Do _not_ access the chip, after it is detached. */
3290 iounmap(bcm->mmio_addr);
3291
3292 pci_release_regions(pci_dev);
3293 pci_disable_device(pci_dev);
3294
3295 /* Free allocated structures/fields */
3296 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003297 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3298 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3299 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
John W. Linvillef2223132006-01-23 16:59:58 -05003300 }
3301}
3302
3303static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3304{
Michael Buesche9357c02006-03-13 19:27:34 +01003305 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003306 u16 value;
3307 u8 phy_version;
3308 u8 phy_type;
3309 u8 phy_rev;
3310 int phy_rev_ok = 1;
3311 void *p;
3312
3313 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3314
3315 phy_version = (value & 0xF000) >> 12;
3316 phy_type = (value & 0x0F00) >> 8;
3317 phy_rev = (value & 0x000F);
3318
3319 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3320 phy_version, phy_type, phy_rev);
3321
3322 switch (phy_type) {
3323 case BCM43xx_PHYTYPE_A:
3324 if (phy_rev >= 4)
3325 phy_rev_ok = 0;
3326 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3327 * if we switch 80211 cores after init is done.
3328 * As we do not implement on the fly switching between
3329 * wireless cores, I will leave this as a future task.
3330 */
3331 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3332 bcm->ieee->mode = IEEE_A;
3333 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3334 IEEE80211_24GHZ_BAND;
3335 break;
3336 case BCM43xx_PHYTYPE_B:
3337 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3338 phy_rev_ok = 0;
3339 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3340 bcm->ieee->mode = IEEE_B;
3341 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3342 break;
3343 case BCM43xx_PHYTYPE_G:
3344 if (phy_rev > 7)
3345 phy_rev_ok = 0;
3346 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3347 IEEE80211_CCK_MODULATION;
3348 bcm->ieee->mode = IEEE_G;
3349 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3350 break;
3351 default:
3352 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3353 phy_type);
3354 return -ENODEV;
3355 };
3356 if (!phy_rev_ok) {
3357 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3358 phy_rev);
3359 }
3360
Michael Buesch489423c2006-02-13 00:11:07 +01003361 phy->version = phy_version;
3362 phy->type = phy_type;
3363 phy->rev = phy_rev;
John W. Linvillef2223132006-01-23 16:59:58 -05003364 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3365 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3366 GFP_KERNEL);
3367 if (!p)
3368 return -ENOMEM;
Michael Buesch489423c2006-02-13 00:11:07 +01003369 phy->_lo_pairs = p;
John W. Linvillef2223132006-01-23 16:59:58 -05003370 }
3371
3372 return 0;
3373}
3374
3375static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3376{
3377 struct pci_dev *pci_dev = bcm->pci_dev;
3378 struct net_device *net_dev = bcm->net_dev;
3379 int err;
3380 int i;
Michael Buesch4a1821e2006-03-18 20:19:12 +01003381 unsigned long mmio_start, mmio_flags, mmio_len;
John W. Linvillef2223132006-01-23 16:59:58 -05003382 u32 coremask;
3383
3384 err = pci_enable_device(pci_dev);
3385 if (err) {
3386 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
John W. Linvillef2223132006-01-23 16:59:58 -05003387 goto out;
3388 }
John W. Linvillef2223132006-01-23 16:59:58 -05003389 mmio_start = pci_resource_start(pci_dev, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05003390 mmio_flags = pci_resource_flags(pci_dev, 0);
3391 mmio_len = pci_resource_len(pci_dev, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05003392 if (!(mmio_flags & IORESOURCE_MEM)) {
3393 printk(KERN_ERR PFX
3394 "%s, region #0 not an MMIO resource, aborting\n",
3395 pci_name(pci_dev));
3396 err = -ENODEV;
3397 goto err_pci_disable;
3398 }
Michael Buesch65f3f192006-01-31 20:11:38 +01003399 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
John W. Linvillef2223132006-01-23 16:59:58 -05003400 if (err) {
3401 printk(KERN_ERR PFX
3402 "could not access PCI resources (%i)\n", err);
3403 goto err_pci_disable;
3404 }
John W. Linvillef2223132006-01-23 16:59:58 -05003405 /* enable PCI bus-mastering */
3406 pci_set_master(pci_dev);
Michael Buesch4a1821e2006-03-18 20:19:12 +01003407 bcm->mmio_addr = ioremap(mmio_start, mmio_len);
3408 if (!bcm->mmio_addr) {
John W. Linvillef2223132006-01-23 16:59:58 -05003409 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3410 pci_name(pci_dev));
3411 err = -EIO;
3412 goto err_pci_release;
3413 }
John W. Linvillef2223132006-01-23 16:59:58 -05003414 bcm->mmio_len = mmio_len;
Michael Buesch4a1821e2006-03-18 20:19:12 +01003415 net_dev->base_addr = (unsigned long)bcm->mmio_addr;
John W. Linvillef2223132006-01-23 16:59:58 -05003416
3417 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3418 &bcm->board_vendor);
3419 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3420 &bcm->board_type);
3421 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3422 &bcm->board_revision);
3423
3424 err = bcm43xx_chipset_attach(bcm);
3425 if (err)
3426 goto err_iounmap;
3427 err = bcm43xx_pctl_init(bcm);
3428 if (err)
3429 goto err_chipset_detach;
3430 err = bcm43xx_probe_cores(bcm);
3431 if (err)
3432 goto err_chipset_detach;
3433
John W. Linvillef2223132006-01-23 16:59:58 -05003434 /* Attach all IO cores to the backplane. */
3435 coremask = 0;
Michael Buesche9357c02006-03-13 19:27:34 +01003436 for (i = 0; i < bcm->nr_80211_available; i++)
John W. Linvillef2223132006-01-23 16:59:58 -05003437 coremask |= (1 << bcm->core_80211[i].index);
3438 //FIXME: Also attach some non80211 cores?
3439 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3440 if (err) {
3441 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3442 goto err_chipset_detach;
3443 }
3444
Michael Bueschea0922b2006-02-19 14:09:20 +01003445 err = bcm43xx_sprom_extract(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003446 if (err)
3447 goto err_chipset_detach;
3448 err = bcm43xx_leds_init(bcm);
3449 if (err)
3450 goto err_chipset_detach;
3451
Michael Buesche9357c02006-03-13 19:27:34 +01003452 for (i = 0; i < bcm->nr_80211_available; i++) {
John W. Linvillef2223132006-01-23 16:59:58 -05003453 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3454 assert(err != -ENODEV);
3455 if (err)
3456 goto err_80211_unwind;
3457
3458 /* Enable the selected wireless core.
3459 * Connect PHY only on the first core.
3460 */
3461 bcm43xx_wireless_core_reset(bcm, (i == 0));
3462
3463 err = bcm43xx_read_phyinfo(bcm);
3464 if (err && (i == 0))
3465 goto err_80211_unwind;
3466
3467 err = bcm43xx_read_radioinfo(bcm);
3468 if (err && (i == 0))
3469 goto err_80211_unwind;
3470
3471 err = bcm43xx_validate_chip(bcm);
3472 if (err && (i == 0))
3473 goto err_80211_unwind;
3474
3475 bcm43xx_radio_turn_off(bcm);
3476 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3477 if (err)
3478 goto err_80211_unwind;
3479 bcm43xx_wireless_core_disable(bcm);
3480 }
3481 bcm43xx_pctl_set_crystal(bcm, 0);
3482
3483 /* Set the MAC address in the networking subsystem */
Michael Buesche9357c02006-03-13 19:27:34 +01003484 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
John W. Linvillef2223132006-01-23 16:59:58 -05003485 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3486 else
3487 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3488
3489 bcm43xx_geo_init(bcm);
3490
3491 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3492 "Broadcom %04X", bcm->chip_id);
3493
3494 assert(err == 0);
3495out:
3496 return err;
3497
3498err_80211_unwind:
3499 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003500 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3501 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3502 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
John W. Linvillef2223132006-01-23 16:59:58 -05003503 }
3504err_chipset_detach:
3505 bcm43xx_chipset_detach(bcm);
3506err_iounmap:
3507 iounmap(bcm->mmio_addr);
3508err_pci_release:
3509 pci_release_regions(pci_dev);
3510err_pci_disable:
3511 pci_disable_device(pci_dev);
3512 goto out;
3513}
3514
John W. Linvillef2223132006-01-23 16:59:58 -05003515/* Do the Hardware IO operations to send the txb */
3516static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3517 struct ieee80211_txb *txb)
3518{
3519 int err = -ENODEV;
3520
Michael Buesch77db31e2006-02-12 16:47:44 +01003521 if (bcm43xx_using_pio(bcm))
3522 err = bcm43xx_pio_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003523 else
Michael Bueschea72ab22006-01-27 17:26:20 +01003524 err = bcm43xx_dma_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003525
3526 return err;
3527}
3528
3529static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3530 u8 channel)
3531{
3532 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschec483782006-03-27 11:49:51 +02003533 struct bcm43xx_radioinfo *radio;
John W. Linvillef2223132006-01-23 16:59:58 -05003534 unsigned long flags;
3535
Michael Bueschefccb642006-03-11 13:39:14 +01003536 bcm43xx_lock_mmio(bcm, flags);
Michael Bueschec483782006-03-27 11:49:51 +02003537 if (bcm->initialized) {
3538 bcm43xx_mac_suspend(bcm);
3539 bcm43xx_radio_selectchannel(bcm, channel, 0);
3540 bcm43xx_mac_enable(bcm);
3541 } else {
3542 radio = bcm43xx_current_radio(bcm);
3543 radio->initial_channel = channel;
3544 }
Michael Bueschefccb642006-03-11 13:39:14 +01003545 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003546}
3547
3548/* set_security() callback in struct ieee80211_device */
3549static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
3550 struct ieee80211_security *sec)
3551{
3552 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3553 struct ieee80211_security *secinfo = &bcm->ieee->sec;
3554 unsigned long flags;
3555 int keyidx;
3556
3557 dprintk(KERN_INFO PFX "set security called\n");
Michael Bueschefccb642006-03-11 13:39:14 +01003558
3559 bcm43xx_lock_mmio(bcm, flags);
3560
John W. Linvillef2223132006-01-23 16:59:58 -05003561 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
3562 if (sec->flags & (1<<keyidx)) {
3563 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
3564 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
3565 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
3566 }
3567
3568 if (sec->flags & SEC_ACTIVE_KEY) {
3569 secinfo->active_key = sec->active_key;
3570 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
3571 }
3572 if (sec->flags & SEC_UNICAST_GROUP) {
3573 secinfo->unicast_uses_group = sec->unicast_uses_group;
3574 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
3575 }
3576 if (sec->flags & SEC_LEVEL) {
3577 secinfo->level = sec->level;
3578 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
3579 }
3580 if (sec->flags & SEC_ENABLED) {
3581 secinfo->enabled = sec->enabled;
3582 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
3583 }
3584 if (sec->flags & SEC_ENCRYPT) {
3585 secinfo->encrypt = sec->encrypt;
3586 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
3587 }
3588 if (bcm->initialized && !bcm->ieee->host_encrypt) {
3589 if (secinfo->enabled) {
3590 /* upload WEP keys to hardware */
3591 char null_address[6] = { 0 };
3592 u8 algorithm = 0;
3593 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
3594 if (!(sec->flags & (1<<keyidx)))
3595 continue;
3596 switch (sec->encode_alg[keyidx]) {
3597 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
3598 case SEC_ALG_WEP:
3599 algorithm = BCM43xx_SEC_ALGO_WEP;
3600 if (secinfo->key_sizes[keyidx] == 13)
3601 algorithm = BCM43xx_SEC_ALGO_WEP104;
3602 break;
3603 case SEC_ALG_TKIP:
3604 FIXME();
3605 algorithm = BCM43xx_SEC_ALGO_TKIP;
3606 break;
3607 case SEC_ALG_CCMP:
3608 FIXME();
3609 algorithm = BCM43xx_SEC_ALGO_AES;
3610 break;
3611 default:
3612 assert(0);
3613 break;
3614 }
3615 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
3616 bcm->key[keyidx].enabled = 1;
3617 bcm->key[keyidx].algorithm = algorithm;
3618 }
3619 } else
3620 bcm43xx_clear_keys(bcm);
3621 }
Michael Bueschefccb642006-03-11 13:39:14 +01003622 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003623}
3624
3625/* hard_start_xmit() callback in struct ieee80211_device */
3626static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
3627 struct net_device *net_dev,
3628 int pri)
3629{
3630 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3631 int err = -ENODEV;
3632 unsigned long flags;
3633
Michael Bueschefccb642006-03-11 13:39:14 +01003634 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003635 if (likely(bcm->initialized))
3636 err = bcm43xx_tx(bcm, txb);
Michael Bueschefccb642006-03-11 13:39:14 +01003637 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003638
3639 return err;
3640}
3641
3642static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
3643{
3644 return &(bcm43xx_priv(net_dev)->ieee->stats);
3645}
3646
3647static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
3648{
3649 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschefccb642006-03-11 13:39:14 +01003650 unsigned long flags;
John W. Linvillef2223132006-01-23 16:59:58 -05003651
Michael Bueschefccb642006-03-11 13:39:14 +01003652 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003653 bcm43xx_controller_restart(bcm, "TX timeout");
Michael Bueschefccb642006-03-11 13:39:14 +01003654 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003655}
3656
3657#ifdef CONFIG_NET_POLL_CONTROLLER
3658static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3659{
3660 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3661 unsigned long flags;
3662
3663 local_irq_save(flags);
3664 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3665 local_irq_restore(flags);
3666}
3667#endif /* CONFIG_NET_POLL_CONTROLLER */
3668
3669static int bcm43xx_net_open(struct net_device *net_dev)
3670{
3671 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3672
3673 return bcm43xx_init_board(bcm);
3674}
3675
3676static int bcm43xx_net_stop(struct net_device *net_dev)
3677{
3678 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3679
3680 ieee80211softmac_stop(net_dev);
3681 bcm43xx_disable_interrupts_sync(bcm, NULL);
3682 bcm43xx_free_board(bcm);
3683
3684 return 0;
3685}
3686
Michael Buesch77db31e2006-02-12 16:47:44 +01003687static int bcm43xx_init_private(struct bcm43xx_private *bcm,
3688 struct net_device *net_dev,
Michael Bueschab4977f2006-02-12 22:40:39 +01003689 struct pci_dev *pci_dev)
John W. Linvillef2223132006-01-23 16:59:58 -05003690{
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003691 int err;
3692
John W. Linvillef2223132006-01-23 16:59:58 -05003693 bcm->ieee = netdev_priv(net_dev);
3694 bcm->softmac = ieee80211_priv(net_dev);
3695 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
John W. Linvillef2223132006-01-23 16:59:58 -05003696
John W. Linvillef2223132006-01-23 16:59:58 -05003697 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3698 bcm->pci_dev = pci_dev;
3699 bcm->net_dev = net_dev;
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003700 bcm->bad_frames_preempt = modparam_bad_frames_preempt;
Michael Bueschefccb642006-03-11 13:39:14 +01003701 spin_lock_init(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05003702 tasklet_init(&bcm->isr_tasklet,
3703 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
3704 (unsigned long)bcm);
3705 tasklet_disable_nosync(&bcm->isr_tasklet);
3706 if (modparam_pio) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003707 bcm->__using_pio = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05003708 } else {
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003709 err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
3710 err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
3711 if (err) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003712#ifdef CONFIG_BCM43XX_PIO
John W. Linvillef2223132006-01-23 16:59:58 -05003713 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
Michael Buesch77db31e2006-02-12 16:47:44 +01003714 bcm->__using_pio = 1;
3715#else
3716 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
3717 "Recompile the driver with PIO support, please.\n");
3718 return -ENODEV;
3719#endif /* CONFIG_BCM43XX_PIO */
John W. Linvillef2223132006-01-23 16:59:58 -05003720 }
3721 }
3722 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
3723
3724 /* default to sw encryption for now */
3725 bcm->ieee->host_build_iv = 0;
3726 bcm->ieee->host_encrypt = 1;
3727 bcm->ieee->host_decrypt = 1;
3728
3729 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
3730 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
3731 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
3732 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
Michael Buesch77db31e2006-02-12 16:47:44 +01003733
3734 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05003735}
3736
3737static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
3738 const struct pci_device_id *ent)
3739{
3740 struct net_device *net_dev;
3741 struct bcm43xx_private *bcm;
John W. Linvillef2223132006-01-23 16:59:58 -05003742 int err;
3743
3744#ifdef CONFIG_BCM947XX
3745 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
3746 return -ENODEV;
3747#endif
3748
3749#ifdef DEBUG_SINGLE_DEVICE_ONLY
3750 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
3751 return -ENODEV;
3752#endif
3753
3754 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
3755 if (!net_dev) {
3756 printk(KERN_ERR PFX
3757 "could not allocate ieee80211 device %s\n",
3758 pci_name(pdev));
3759 err = -ENOMEM;
3760 goto out;
3761 }
3762 /* initialize the net_device struct */
3763 SET_MODULE_OWNER(net_dev);
3764 SET_NETDEV_DEV(net_dev, &pdev->dev);
3765
3766 net_dev->open = bcm43xx_net_open;
3767 net_dev->stop = bcm43xx_net_stop;
3768 net_dev->get_stats = bcm43xx_net_get_stats;
3769 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
3770#ifdef CONFIG_NET_POLL_CONTROLLER
3771 net_dev->poll_controller = bcm43xx_net_poll_controller;
3772#endif
3773 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
3774 net_dev->irq = pdev->irq;
Michael Buesch6465ce12006-02-02 19:11:08 +01003775 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
John W. Linvillef2223132006-01-23 16:59:58 -05003776
3777 /* initialize the bcm43xx_private struct */
3778 bcm = bcm43xx_priv(net_dev);
3779 memset(bcm, 0, sizeof(*bcm));
Michael Bueschab4977f2006-02-12 22:40:39 +01003780 err = bcm43xx_init_private(bcm, net_dev, pdev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003781 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003782 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003783
3784 pci_set_drvdata(pdev, net_dev);
3785
3786 err = bcm43xx_attach_board(bcm);
3787 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003788 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003789
3790 err = register_netdev(net_dev);
3791 if (err) {
3792 printk(KERN_ERR PFX "Cannot register net device, "
3793 "aborting.\n");
3794 err = -ENOMEM;
3795 goto err_detach_board;
3796 }
3797
3798 bcm43xx_debugfs_add_device(bcm);
3799
3800 assert(err == 0);
3801out:
3802 return err;
3803
3804err_detach_board:
3805 bcm43xx_detach_board(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003806err_free_netdev:
3807 free_ieee80211softmac(net_dev);
3808 goto out;
3809}
3810
3811static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3812{
3813 struct net_device *net_dev = pci_get_drvdata(pdev);
3814 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3815
3816 bcm43xx_debugfs_remove_device(bcm);
3817 unregister_netdev(net_dev);
3818 bcm43xx_detach_board(bcm);
3819 assert(bcm->ucode == NULL);
John W. Linvillef2223132006-01-23 16:59:58 -05003820 free_ieee80211softmac(net_dev);
3821}
3822
3823/* Hard-reset the chip. Do not call this directly.
3824 * Use bcm43xx_controller_restart()
3825 */
3826static void bcm43xx_chip_reset(void *_bcm)
3827{
3828 struct bcm43xx_private *bcm = _bcm;
3829 struct net_device *net_dev = bcm->net_dev;
3830 struct pci_dev *pci_dev = bcm->pci_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05003831 int err;
3832 int was_initialized = bcm->initialized;
3833
3834 netif_stop_queue(bcm->net_dev);
3835 tasklet_disable(&bcm->isr_tasklet);
3836
3837 bcm->firmware_norelease = 1;
3838 if (was_initialized)
3839 bcm43xx_free_board(bcm);
3840 bcm->firmware_norelease = 0;
3841 bcm43xx_detach_board(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003842 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003843 if (err)
3844 goto failure;
John W. Linvillef2223132006-01-23 16:59:58 -05003845 err = bcm43xx_attach_board(bcm);
3846 if (err)
3847 goto failure;
3848 if (was_initialized) {
3849 err = bcm43xx_init_board(bcm);
3850 if (err)
3851 goto failure;
3852 }
3853 netif_wake_queue(bcm->net_dev);
3854 printk(KERN_INFO PFX "Controller restarted\n");
3855
3856 return;
3857failure:
3858 printk(KERN_ERR PFX "Controller restart failed\n");
3859}
3860
3861/* Hard-reset the chip.
3862 * This can be called from interrupt or process context.
3863 * Make sure to _not_ re-enable device interrupts after this has been called.
3864*/
3865void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
3866{
3867 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
Michael Buesch73733842006-03-12 19:44:29 +01003868 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
John W. Linvillef2223132006-01-23 16:59:58 -05003869 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
3870 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003871 schedule_work(&bcm->restart_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003872}
3873
3874#ifdef CONFIG_PM
3875
3876static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
3877{
3878 struct net_device *net_dev = pci_get_drvdata(pdev);
3879 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3880 unsigned long flags;
3881 int try_to_shutdown = 0, err;
3882
3883 dprintk(KERN_INFO PFX "Suspending...\n");
3884
Michael Bueschefccb642006-03-11 13:39:14 +01003885 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003886 bcm->was_initialized = bcm->initialized;
3887 if (bcm->initialized)
3888 try_to_shutdown = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003889 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003890
3891 netif_device_detach(net_dev);
3892 if (try_to_shutdown) {
3893 ieee80211softmac_stop(net_dev);
3894 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
3895 if (unlikely(err)) {
3896 dprintk(KERN_ERR PFX "Suspend failed.\n");
3897 return -EAGAIN;
3898 }
3899 bcm->firmware_norelease = 1;
3900 bcm43xx_free_board(bcm);
3901 bcm->firmware_norelease = 0;
3902 }
3903 bcm43xx_chipset_detach(bcm);
3904
3905 pci_save_state(pdev);
3906 pci_disable_device(pdev);
3907 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3908
3909 dprintk(KERN_INFO PFX "Device suspended.\n");
3910
3911 return 0;
3912}
3913
3914static int bcm43xx_resume(struct pci_dev *pdev)
3915{
3916 struct net_device *net_dev = pci_get_drvdata(pdev);
3917 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3918 int err = 0;
3919
3920 dprintk(KERN_INFO PFX "Resuming...\n");
3921
3922 pci_set_power_state(pdev, 0);
3923 pci_enable_device(pdev);
3924 pci_restore_state(pdev);
3925
3926 bcm43xx_chipset_attach(bcm);
3927 if (bcm->was_initialized) {
3928 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3929 err = bcm43xx_init_board(bcm);
3930 }
3931 if (err) {
3932 printk(KERN_ERR PFX "Resume failed!\n");
3933 return err;
3934 }
3935
3936 netif_device_attach(net_dev);
3937
3938 /*FIXME: This should be handled by softmac instead. */
3939 schedule_work(&bcm->softmac->associnfo.work);
3940
3941 dprintk(KERN_INFO PFX "Device resumed.\n");
3942
3943 return 0;
3944}
3945
3946#endif /* CONFIG_PM */
3947
3948static struct pci_driver bcm43xx_pci_driver = {
Michael Buesch65f3f192006-01-31 20:11:38 +01003949 .name = KBUILD_MODNAME,
John W. Linvillef2223132006-01-23 16:59:58 -05003950 .id_table = bcm43xx_pci_tbl,
3951 .probe = bcm43xx_init_one,
3952 .remove = __devexit_p(bcm43xx_remove_one),
3953#ifdef CONFIG_PM
3954 .suspend = bcm43xx_suspend,
3955 .resume = bcm43xx_resume,
3956#endif /* CONFIG_PM */
3957};
3958
3959static int __init bcm43xx_init(void)
3960{
Michael Buesch65f3f192006-01-31 20:11:38 +01003961 printk(KERN_INFO KBUILD_MODNAME " driver\n");
John W. Linvillef2223132006-01-23 16:59:58 -05003962 bcm43xx_debugfs_init();
3963 return pci_register_driver(&bcm43xx_pci_driver);
3964}
3965
3966static void __exit bcm43xx_exit(void)
3967{
3968 pci_unregister_driver(&bcm43xx_pci_driver);
3969 bcm43xx_debugfs_exit();
3970}
3971
3972module_init(bcm43xx_init)
3973module_exit(bcm43xx_exit)