blob: 7c1d72fc628993ff12548911b77a3be0f00d920d [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 Buesche9357c02006-03-13 19:27:34 +0100573 if (phy->type == BCM43xx_PHYTYPE_A)
Michael Buesch489423c2006-02-13 00:11:07 +0100574 radio->txpower_desired = bcm->sprom.maxpower_aphy;
Michael Buesch393344f2006-02-05 15:28:20 +0100575 else
Michael Buesche9357c02006-03-13 19:27:34 +0100576 radio->txpower_desired = bcm->sprom.maxpower_bgphy;
John W. Linvillef2223132006-01-23 16:59:58 -0500577
578 /* Initialize the in-memory nrssi Lookup Table. */
579 for (i = 0; i < 64; i++)
Michael Buesch489423c2006-02-13 00:11:07 +0100580 radio->nrssi_lt[i] = i;
John W. Linvillef2223132006-01-23 16:59:58 -0500581
582 return 0;
583
584err_unsupported_radio:
585 printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
586 return -ENODEV;
587}
588
589static const char * bcm43xx_locale_iso(u8 locale)
590{
591 /* ISO 3166-1 country codes.
592 * Note that there aren't ISO 3166-1 codes for
593 * all or locales. (Not all locales are countries)
594 */
595 switch (locale) {
596 case BCM43xx_LOCALE_WORLD:
597 case BCM43xx_LOCALE_ALL:
598 return "XX";
599 case BCM43xx_LOCALE_THAILAND:
600 return "TH";
601 case BCM43xx_LOCALE_ISRAEL:
602 return "IL";
603 case BCM43xx_LOCALE_JORDAN:
604 return "JO";
605 case BCM43xx_LOCALE_CHINA:
606 return "CN";
607 case BCM43xx_LOCALE_JAPAN:
608 case BCM43xx_LOCALE_JAPAN_HIGH:
609 return "JP";
610 case BCM43xx_LOCALE_USA_CANADA_ANZ:
611 case BCM43xx_LOCALE_USA_LOW:
612 return "US";
613 case BCM43xx_LOCALE_EUROPE:
614 return "EU";
615 case BCM43xx_LOCALE_NONE:
616 return " ";
617 }
618 assert(0);
619 return " ";
620}
621
622static const char * bcm43xx_locale_string(u8 locale)
623{
624 switch (locale) {
625 case BCM43xx_LOCALE_WORLD:
626 return "World";
627 case BCM43xx_LOCALE_THAILAND:
628 return "Thailand";
629 case BCM43xx_LOCALE_ISRAEL:
630 return "Israel";
631 case BCM43xx_LOCALE_JORDAN:
632 return "Jordan";
633 case BCM43xx_LOCALE_CHINA:
634 return "China";
635 case BCM43xx_LOCALE_JAPAN:
636 return "Japan";
637 case BCM43xx_LOCALE_USA_CANADA_ANZ:
638 return "USA/Canada/ANZ";
639 case BCM43xx_LOCALE_EUROPE:
640 return "Europe";
641 case BCM43xx_LOCALE_USA_LOW:
642 return "USAlow";
643 case BCM43xx_LOCALE_JAPAN_HIGH:
644 return "JapanHigh";
645 case BCM43xx_LOCALE_ALL:
646 return "All";
647 case BCM43xx_LOCALE_NONE:
648 return "None";
649 }
650 assert(0);
651 return "";
652}
653
654static inline u8 bcm43xx_crc8(u8 crc, u8 data)
655{
656 static const u8 t[] = {
657 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
658 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
659 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
660 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
661 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
662 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
663 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
664 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
665 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
666 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
667 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
668 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
669 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
670 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
671 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
672 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
673 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
674 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
675 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
676 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
677 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
678 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
679 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
680 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
681 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
682 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
683 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
684 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
685 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
686 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
687 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
688 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
689 };
690 return t[crc ^ data];
691}
692
Michael Bueschad3f0862006-02-19 14:12:22 +0100693static u8 bcm43xx_sprom_crc(const u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500694{
695 int word;
696 u8 crc = 0xFF;
697
698 for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
699 crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
700 crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
701 }
702 crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
703 crc ^= 0xFF;
704
705 return crc;
706}
707
Michael Bueschea0922b2006-02-19 14:09:20 +0100708int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500709{
710 int i;
Michael Bueschea0922b2006-02-19 14:09:20 +0100711 u8 crc, expected_crc;
712
713 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
714 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
715 /* CRC-8 check. */
716 crc = bcm43xx_sprom_crc(sprom);
717 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
718 if (crc != expected_crc) {
719 printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
720 "(0x%02X, expected: 0x%02X)\n",
721 crc, expected_crc);
722 return -EINVAL;
723 }
724
725 return 0;
726}
727
728int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
729{
730 int i, err;
731 u8 crc, expected_crc;
732 u32 spromctl;
733
734 /* CRC-8 validation of the input data. */
735 crc = bcm43xx_sprom_crc(sprom);
736 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
737 if (crc != expected_crc) {
738 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
739 return -EINVAL;
740 }
741
742 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
743 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
744 if (err)
745 goto err_ctlreg;
746 spromctl |= 0x10; /* SPROM WRITE enable. */
747 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
748 if (err)
749 goto err_ctlreg;
750 /* We must burn lots of CPU cycles here, but that does not
751 * really matter as one does not write the SPROM every other minute...
752 */
753 printk(KERN_INFO PFX "[ 0%%");
754 mdelay(500);
755 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
756 if (i == 16)
757 printk("25%%");
758 else if (i == 32)
759 printk("50%%");
760 else if (i == 48)
761 printk("75%%");
762 else if (i % 2)
763 printk(".");
764 bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
Michael Bueschefccb642006-03-11 13:39:14 +0100765 mmiowb();
Michael Bueschea0922b2006-02-19 14:09:20 +0100766 mdelay(20);
767 }
768 spromctl &= ~0x10; /* SPROM WRITE enable. */
769 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
770 if (err)
771 goto err_ctlreg;
772 mdelay(500);
773 printk("100%% ]\n");
774 printk(KERN_INFO PFX "SPROM written.\n");
775 bcm43xx_controller_restart(bcm, "SPROM update");
776
777 return 0;
778err_ctlreg:
779 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
780 return -ENODEV;
781}
782
783static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
784{
John W. Linvillef2223132006-01-23 16:59:58 -0500785 u16 value;
786 u16 *sprom;
John W. Linvillef2223132006-01-23 16:59:58 -0500787#ifdef CONFIG_BCM947XX
788 char *c;
789#endif
790
791 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
792 GFP_KERNEL);
793 if (!sprom) {
Michael Bueschea0922b2006-02-19 14:09:20 +0100794 printk(KERN_ERR PFX "sprom_extract OOM\n");
John W. Linvillef2223132006-01-23 16:59:58 -0500795 return -ENOMEM;
796 }
797#ifdef CONFIG_BCM947XX
798 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
799 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
800
801 if ((c = nvram_get("il0macaddr")) != NULL)
802 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
803
804 if ((c = nvram_get("et1macaddr")) != NULL)
805 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
806
807 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
808 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
809 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
810
811 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
812 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
813 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
814
815 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
816#else
Michael Bueschea0922b2006-02-19 14:09:20 +0100817 bcm43xx_sprom_read(bcm, sprom);
John W. Linvillef2223132006-01-23 16:59:58 -0500818#endif
819
820 /* boardflags2 */
821 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
822 bcm->sprom.boardflags2 = value;
823
824 /* il0macaddr */
825 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
826 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
827 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
828 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
829 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
830 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
831
832 /* et0macaddr */
833 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
834 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
835 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
836 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
837 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
838 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
839
840 /* et1macaddr */
841 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
842 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
843 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
844 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
845 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
846 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
847
848 /* ethernet phy settings */
849 value = sprom[BCM43xx_SPROM_ETHPHY];
850 bcm->sprom.et0phyaddr = (value & 0x001F);
851 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
852 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
853 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
854
855 /* boardrev, antennas, locale */
856 value = sprom[BCM43xx_SPROM_BOARDREV];
857 bcm->sprom.boardrev = (value & 0x00FF);
858 bcm->sprom.locale = (value & 0x0F00) >> 8;
859 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
860 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
861 if (modparam_locale != -1) {
862 if (modparam_locale >= 0 && modparam_locale <= 11) {
863 bcm->sprom.locale = modparam_locale;
864 printk(KERN_WARNING PFX "Operating with modified "
865 "LocaleCode %u (%s)\n",
866 bcm->sprom.locale,
867 bcm43xx_locale_string(bcm->sprom.locale));
868 } else {
869 printk(KERN_WARNING PFX "Module parameter \"locale\" "
870 "invalid value. (0 - 11)\n");
871 }
872 }
873
874 /* pa0b* */
875 value = sprom[BCM43xx_SPROM_PA0B0];
876 bcm->sprom.pa0b0 = value;
877 value = sprom[BCM43xx_SPROM_PA0B1];
878 bcm->sprom.pa0b1 = value;
879 value = sprom[BCM43xx_SPROM_PA0B2];
880 bcm->sprom.pa0b2 = value;
881
882 /* wl0gpio* */
883 value = sprom[BCM43xx_SPROM_WL0GPIO0];
884 if (value == 0x0000)
885 value = 0xFFFF;
886 bcm->sprom.wl0gpio0 = value & 0x00FF;
887 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
888 value = sprom[BCM43xx_SPROM_WL0GPIO2];
889 if (value == 0x0000)
890 value = 0xFFFF;
891 bcm->sprom.wl0gpio2 = value & 0x00FF;
892 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
893
894 /* maxpower */
895 value = sprom[BCM43xx_SPROM_MAXPWR];
896 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
897 bcm->sprom.maxpower_bgphy = value & 0x00FF;
898
899 /* pa1b* */
900 value = sprom[BCM43xx_SPROM_PA1B0];
901 bcm->sprom.pa1b0 = value;
902 value = sprom[BCM43xx_SPROM_PA1B1];
903 bcm->sprom.pa1b1 = value;
904 value = sprom[BCM43xx_SPROM_PA1B2];
905 bcm->sprom.pa1b2 = value;
906
907 /* idle tssi target */
908 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
909 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
910 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
911
912 /* boardflags */
913 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
914 if (value == 0xFFFF)
915 value = 0x0000;
916 bcm->sprom.boardflags = value;
Michael Bueschb3db5e52006-03-15 16:31:45 +0100917 /* boardflags workarounds */
918 if (bcm->board_vendor == PCI_VENDOR_ID_DELL &&
919 bcm->chip_id == 0x4301 &&
920 bcm->board_revision == 0x74)
921 bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST;
922 if (bcm->board_vendor == PCI_VENDOR_ID_APPLE &&
923 bcm->board_type == 0x4E &&
924 bcm->board_revision > 0x40)
925 bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL;
John W. Linvillef2223132006-01-23 16:59:58 -0500926
927 /* antenna gain */
928 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
929 if (value == 0x0000 || value == 0xFFFF)
930 value = 0x0202;
931 /* convert values to Q5.2 */
932 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
933 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
934
935 kfree(sprom);
936
937 return 0;
938}
939
John W. Linvillef2223132006-01-23 16:59:58 -0500940static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
941{
942 struct ieee80211_geo geo;
943 struct ieee80211_channel *chan;
944 int have_a = 0, have_bg = 0;
Michael Buesche9357c02006-03-13 19:27:34 +0100945 int i;
Michael Buesch9e4a3752006-02-02 18:43:25 +0100946 u8 channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500947 struct bcm43xx_phyinfo *phy;
948 const char *iso_country;
949
950 memset(&geo, 0, sizeof(geo));
Michael Buesche9357c02006-03-13 19:27:34 +0100951 for (i = 0; i < bcm->nr_80211_available; i++) {
952 phy = &(bcm->core_80211_ext[i].phy);
John W. Linvillef2223132006-01-23 16:59:58 -0500953 switch (phy->type) {
954 case BCM43xx_PHYTYPE_B:
955 case BCM43xx_PHYTYPE_G:
956 have_bg = 1;
957 break;
958 case BCM43xx_PHYTYPE_A:
959 have_a = 1;
960 break;
961 default:
962 assert(0);
963 }
964 }
965 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
966
967 if (have_a) {
968 for (i = 0, channel = 0; channel < 201; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500969 chan = &geo.a[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100970 chan->freq = bcm43xx_channel_to_freq_a(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500971 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500972 }
973 geo.a_channels = i;
974 }
975 if (have_bg) {
976 for (i = 0, channel = 1; channel < 15; channel++) {
John W. Linvillef2223132006-01-23 16:59:58 -0500977 chan = &geo.bg[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100978 chan->freq = bcm43xx_channel_to_freq_bg(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500979 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500980 }
981 geo.bg_channels = i;
982 }
983 memcpy(geo.name, iso_country, 2);
984 if (0 /*TODO: Outdoor use only */)
985 geo.name[2] = 'O';
986 else if (0 /*TODO: Indoor use only */)
987 geo.name[2] = 'I';
988 else
989 geo.name[2] = ' ';
990 geo.name[3] = '\0';
991
992 ieee80211_set_geo(bcm->ieee, &geo);
993}
994
995/* DummyTransmission function, as documented on
996 * http://bcm-specs.sipsolutions.net/DummyTransmission
997 */
998void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
999{
Michael Buesche9357c02006-03-13 19:27:34 +01001000 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1001 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001002 unsigned int i, max_loop;
1003 u16 value = 0;
1004 u32 buffer[5] = {
1005 0x00000000,
1006 0x0000D400,
1007 0x00000000,
1008 0x00000001,
1009 0x00000000,
1010 };
1011
Michael Buesch489423c2006-02-13 00:11:07 +01001012 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -05001013 case BCM43xx_PHYTYPE_A:
1014 max_loop = 0x1E;
1015 buffer[0] = 0xCC010200;
1016 break;
1017 case BCM43xx_PHYTYPE_B:
1018 case BCM43xx_PHYTYPE_G:
1019 max_loop = 0xFA;
1020 buffer[0] = 0x6E840B00;
1021 break;
1022 default:
1023 assert(0);
1024 return;
1025 }
1026
1027 for (i = 0; i < 5; i++)
1028 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1029
1030 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1031
1032 bcm43xx_write16(bcm, 0x0568, 0x0000);
1033 bcm43xx_write16(bcm, 0x07C0, 0x0000);
Michael Buesch489423c2006-02-13 00:11:07 +01001034 bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
John W. Linvillef2223132006-01-23 16:59:58 -05001035 bcm43xx_write16(bcm, 0x0508, 0x0000);
1036 bcm43xx_write16(bcm, 0x050A, 0x0000);
1037 bcm43xx_write16(bcm, 0x054C, 0x0000);
1038 bcm43xx_write16(bcm, 0x056A, 0x0014);
1039 bcm43xx_write16(bcm, 0x0568, 0x0826);
1040 bcm43xx_write16(bcm, 0x0500, 0x0000);
1041 bcm43xx_write16(bcm, 0x0502, 0x0030);
1042
Michael Buesch73733842006-03-12 19:44:29 +01001043 if (radio->version == 0x2050 && radio->revision <= 0x5)
1044 bcm43xx_radio_write16(bcm, 0x0051, 0x0017);
John W. Linvillef2223132006-01-23 16:59:58 -05001045 for (i = 0x00; i < max_loop; i++) {
1046 value = bcm43xx_read16(bcm, 0x050E);
Michael Buesch73733842006-03-12 19:44:29 +01001047 if (value & 0x0080)
John W. Linvillef2223132006-01-23 16:59:58 -05001048 break;
1049 udelay(10);
1050 }
1051 for (i = 0x00; i < 0x0A; i++) {
1052 value = bcm43xx_read16(bcm, 0x050E);
Michael Buesch73733842006-03-12 19:44:29 +01001053 if (value & 0x0400)
John W. Linvillef2223132006-01-23 16:59:58 -05001054 break;
1055 udelay(10);
1056 }
1057 for (i = 0x00; i < 0x0A; i++) {
1058 value = bcm43xx_read16(bcm, 0x0690);
Michael Buesch73733842006-03-12 19:44:29 +01001059 if (!(value & 0x0100))
John W. Linvillef2223132006-01-23 16:59:58 -05001060 break;
1061 udelay(10);
1062 }
Michael Buesch73733842006-03-12 19:44:29 +01001063 if (radio->version == 0x2050 && radio->revision <= 0x5)
1064 bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
John W. Linvillef2223132006-01-23 16:59:58 -05001065}
1066
1067static void key_write(struct bcm43xx_private *bcm,
1068 u8 index, u8 algorithm, const u16 *key)
1069{
1070 unsigned int i, basic_wep = 0;
1071 u32 offset;
1072 u16 value;
1073
1074 /* Write associated key information */
1075 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1076 ((index << 4) | (algorithm & 0x0F)));
1077
1078 /* The first 4 WEP keys need extra love */
1079 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1080 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1081 basic_wep = 1;
1082
1083 /* Write key payload, 8 little endian words */
1084 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1085 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1086 value = cpu_to_le16(key[i]);
1087 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1088 offset + (i * 2), value);
1089
1090 if (!basic_wep)
1091 continue;
1092
1093 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1094 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1095 value);
1096 }
1097}
1098
1099static void keymac_write(struct bcm43xx_private *bcm,
1100 u8 index, const u32 *addr)
1101{
1102 /* for keys 0-3 there is no associated mac address */
1103 if (index < 4)
1104 return;
1105
1106 index -= 4;
1107 if (bcm->current_core->rev >= 5) {
1108 bcm43xx_shm_write32(bcm,
1109 BCM43xx_SHM_HWMAC,
1110 index * 2,
1111 cpu_to_be32(*addr));
1112 bcm43xx_shm_write16(bcm,
1113 BCM43xx_SHM_HWMAC,
1114 (index * 2) + 1,
1115 cpu_to_be16(*((u16 *)(addr + 1))));
1116 } else {
1117 if (index < 8) {
1118 TODO(); /* Put them in the macaddress filter */
1119 } else {
1120 TODO();
1121 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1122 Keep in mind to update the count of keymacs in 0x003E as well! */
1123 }
1124 }
1125}
1126
1127static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1128 u8 index, u8 algorithm,
1129 const u8 *_key, int key_len,
1130 const u8 *mac_addr)
1131{
1132 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1133
1134 if (index >= ARRAY_SIZE(bcm->key))
1135 return -EINVAL;
1136 if (key_len > ARRAY_SIZE(key))
1137 return -EINVAL;
1138 if (algorithm < 1 || algorithm > 5)
1139 return -EINVAL;
1140
1141 memcpy(key, _key, key_len);
1142 key_write(bcm, index, algorithm, (const u16 *)key);
1143 keymac_write(bcm, index, (const u32 *)mac_addr);
1144
1145 bcm->key[index].algorithm = algorithm;
1146
1147 return 0;
1148}
1149
1150static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1151{
1152 static const u32 zero_mac[2] = { 0 };
1153 unsigned int i,j, nr_keys = 54;
1154 u16 offset;
1155
1156 if (bcm->current_core->rev < 5)
1157 nr_keys = 16;
1158 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1159
1160 for (i = 0; i < nr_keys; i++) {
1161 bcm->key[i].enabled = 0;
1162 /* returns for i < 4 immediately */
1163 keymac_write(bcm, i, zero_mac);
1164 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1165 0x100 + (i * 2), 0x0000);
1166 for (j = 0; j < 8; j++) {
1167 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1168 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1169 offset, 0x0000);
1170 }
1171 }
1172 dprintk(KERN_INFO PFX "Keys cleared\n");
1173}
1174
John W. Linvillef2223132006-01-23 16:59:58 -05001175/* Lowlevel core-switch function. This is only to be used in
1176 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1177 */
1178static int _switch_core(struct bcm43xx_private *bcm, int core)
1179{
1180 int err;
1181 int attempts = 0;
Michael Buesch489423c2006-02-13 00:11:07 +01001182 u32 current_core;
John W. Linvillef2223132006-01-23 16:59:58 -05001183
1184 assert(core >= 0);
Michael Buesch489423c2006-02-13 00:11:07 +01001185 while (1) {
1186 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
John W. Linvillef2223132006-01-23 16:59:58 -05001187 (core * 0x1000) + 0x18000000);
Michael Buesch489423c2006-02-13 00:11:07 +01001188 if (unlikely(err))
1189 goto error;
1190 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1191 &current_core);
1192 if (unlikely(err))
1193 goto error;
1194 current_core = (current_core - 0x18000000) / 0x1000;
1195 if (current_core == core)
1196 break;
John W. Linvillef2223132006-01-23 16:59:58 -05001197
Michael Buesch489423c2006-02-13 00:11:07 +01001198 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
1199 goto error;
1200 udelay(10);
1201 }
1202#ifdef CONFIG_BCM947XX
1203 if (bcm->pci_dev->bus->number == 0)
1204 bcm->current_core_offset = 0x1000 * core;
1205 else
1206 bcm->current_core_offset = 0;
1207#endif
1208
1209 return 0;
1210error:
1211 printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
1212 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05001213}
1214
1215int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1216{
1217 int err;
1218
Michael Buesch489423c2006-02-13 00:11:07 +01001219 if (unlikely(!new_core))
John W. Linvillef2223132006-01-23 16:59:58 -05001220 return 0;
Michael Buesche9357c02006-03-13 19:27:34 +01001221 if (!new_core->available)
John W. Linvillef2223132006-01-23 16:59:58 -05001222 return -ENODEV;
1223 if (bcm->current_core == new_core)
1224 return 0;
1225 err = _switch_core(bcm, new_core->index);
Michael Buesche9357c02006-03-13 19:27:34 +01001226 if (unlikely(err))
1227 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001228
Michael Buesche9357c02006-03-13 19:27:34 +01001229 bcm->current_core = new_core;
1230 bcm->current_80211_core_idx = -1;
1231 if (new_core->id == BCM43xx_COREID_80211)
1232 bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
1233
1234out:
John W. Linvillef2223132006-01-23 16:59:58 -05001235 return err;
1236}
1237
Michael Buesch489423c2006-02-13 00:11:07 +01001238static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001239{
1240 u32 value;
1241
1242 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1243 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1244 | BCM43xx_SBTMSTATELOW_REJECT;
1245
1246 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1247}
1248
1249/* disable current core */
1250static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1251{
1252 u32 sbtmstatelow;
1253 u32 sbtmstatehigh;
1254 int i;
1255
1256 /* fetch sbtmstatelow from core information registers */
1257 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1258
1259 /* core is already in reset */
1260 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1261 goto out;
1262
1263 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1264 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1265 BCM43xx_SBTMSTATELOW_REJECT;
1266 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1267
1268 for (i = 0; i < 1000; i++) {
1269 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1270 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1271 i = -1;
1272 break;
1273 }
1274 udelay(10);
1275 }
1276 if (i != -1) {
1277 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1278 return -EBUSY;
1279 }
1280
1281 for (i = 0; i < 1000; i++) {
1282 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1283 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1284 i = -1;
1285 break;
1286 }
1287 udelay(10);
1288 }
1289 if (i != -1) {
1290 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1291 return -EBUSY;
1292 }
1293
1294 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1295 BCM43xx_SBTMSTATELOW_REJECT |
1296 BCM43xx_SBTMSTATELOW_RESET |
1297 BCM43xx_SBTMSTATELOW_CLOCK |
1298 core_flags;
1299 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1300 udelay(10);
1301 }
1302
1303 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1304 BCM43xx_SBTMSTATELOW_REJECT |
1305 core_flags;
1306 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1307
1308out:
Michael Buesche9357c02006-03-13 19:27:34 +01001309 bcm->current_core->enabled = 0;
1310
John W. Linvillef2223132006-01-23 16:59:58 -05001311 return 0;
1312}
1313
1314/* enable (reset) current core */
1315static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1316{
1317 u32 sbtmstatelow;
1318 u32 sbtmstatehigh;
1319 u32 sbimstate;
1320 int err;
1321
1322 err = bcm43xx_core_disable(bcm, core_flags);
1323 if (err)
1324 goto out;
1325
1326 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1327 BCM43xx_SBTMSTATELOW_RESET |
1328 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1329 core_flags;
1330 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1331 udelay(1);
1332
1333 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1334 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1335 sbtmstatehigh = 0x00000000;
1336 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1337 }
1338
1339 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1340 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1341 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1342 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1343 }
1344
1345 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1346 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1347 core_flags;
1348 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1349 udelay(1);
1350
1351 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1352 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1353 udelay(1);
1354
Michael Buesche9357c02006-03-13 19:27:34 +01001355 bcm->current_core->enabled = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001356 assert(err == 0);
1357out:
1358 return err;
1359}
1360
1361/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1362void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1363{
1364 u32 flags = 0x00040000;
1365
Michael Buesch77db31e2006-02-12 16:47:44 +01001366 if ((bcm43xx_core_enabled(bcm)) &&
1367 !bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05001368//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1369#ifndef CONFIG_BCM947XX
1370 /* reset all used DMA controllers. */
1371 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1372 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1373 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1374 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1375 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1376 if (bcm->current_core->rev < 5)
1377 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1378#endif
1379 }
1380 if (bcm->shutting_down) {
1381 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1382 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1383 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1384 } else {
1385 if (connect_phy)
1386 flags |= 0x20000000;
1387 bcm43xx_phy_connect(bcm, connect_phy);
1388 bcm43xx_core_enable(bcm, flags);
1389 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1390 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1391 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1392 | BCM43xx_SBF_400);
1393 }
1394}
1395
1396static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1397{
1398 bcm43xx_radio_turn_off(bcm);
1399 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1400 bcm43xx_core_disable(bcm, 0);
1401}
1402
1403/* Mark the current 80211 core inactive.
1404 * "active_80211_core" is the other 80211 core, which is used.
1405 */
1406static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1407 struct bcm43xx_coreinfo *active_80211_core)
1408{
1409 u32 sbtmstatelow;
1410 struct bcm43xx_coreinfo *old_core;
1411 int err = 0;
1412
1413 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1414 bcm43xx_radio_turn_off(bcm);
1415 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1416 sbtmstatelow &= ~0x200a0000;
1417 sbtmstatelow |= 0xa0000;
1418 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1419 udelay(1);
1420 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1421 sbtmstatelow &= ~0xa0000;
1422 sbtmstatelow |= 0x80000;
1423 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1424 udelay(1);
1425
Michael Buesche9357c02006-03-13 19:27:34 +01001426 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -05001427 old_core = bcm->current_core;
1428 err = bcm43xx_switch_core(bcm, active_80211_core);
1429 if (err)
1430 goto out;
1431 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1432 sbtmstatelow &= ~0x20000000;
1433 sbtmstatelow |= 0x20000000;
1434 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1435 err = bcm43xx_switch_core(bcm, old_core);
1436 }
1437
1438out:
1439 return err;
1440}
1441
Michael Buesch489423c2006-02-13 00:11:07 +01001442static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001443{
1444 u32 v0, v1;
1445 u16 tmp;
1446 struct bcm43xx_xmitstatus stat;
1447
John W. Linvillef2223132006-01-23 16:59:58 -05001448 while (1) {
1449 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1450 if (!v0)
1451 break;
1452 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1453
1454 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1455 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1456 stat.flags = tmp & 0xFF;
1457 stat.cnt1 = (tmp & 0x0F00) >> 8;
1458 stat.cnt2 = (tmp & 0xF000) >> 12;
1459 stat.seq = (u16)(v1 & 0xFFFF);
1460 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1461
1462 bcm43xx_debugfs_log_txstat(bcm, &stat);
1463
1464 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1465 continue;
1466 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1467 //TODO: packet was not acked (was lost)
1468 }
1469 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1470
Michael Buesch77db31e2006-02-12 16:47:44 +01001471 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001472 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1473 else
1474 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1475 }
1476}
1477
Michael Buesch489423c2006-02-13 00:11:07 +01001478static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001479{
1480 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1481 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1482 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1483 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1484 assert(bcm->noisecalc.core_at_start == bcm->current_core);
Michael Buesche9357c02006-03-13 19:27:34 +01001485 assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);
John W. Linvillef2223132006-01-23 16:59:58 -05001486}
1487
1488static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1489{
1490 /* Top half of Link Quality calculation. */
1491
1492 if (bcm->noisecalc.calculation_running)
1493 return;
1494 bcm->noisecalc.core_at_start = bcm->current_core;
Michael Buesche9357c02006-03-13 19:27:34 +01001495 bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;
John W. Linvillef2223132006-01-23 16:59:58 -05001496 bcm->noisecalc.calculation_running = 1;
1497 bcm->noisecalc.nr_samples = 0;
1498
1499 bcm43xx_generate_noise_sample(bcm);
1500}
1501
Michael Buesch489423c2006-02-13 00:11:07 +01001502static void handle_irq_noise(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001503{
Michael Buesche9357c02006-03-13 19:27:34 +01001504 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001505 u16 tmp;
1506 u8 noise[4];
1507 u8 i, j;
1508 s32 average;
1509
1510 /* Bottom half of Link Quality calculation. */
1511
1512 assert(bcm->noisecalc.calculation_running);
1513 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1514 bcm->noisecalc.channel_at_start != radio->channel)
1515 goto drop_calculation;
1516 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1517 noise[0] = (tmp & 0x00FF);
1518 noise[1] = (tmp & 0xFF00) >> 8;
1519 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1520 noise[2] = (tmp & 0x00FF);
1521 noise[3] = (tmp & 0xFF00) >> 8;
1522 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1523 noise[2] == 0x7F || noise[3] == 0x7F)
1524 goto generate_new;
1525
1526 /* Get the noise samples. */
1527 assert(bcm->noisecalc.nr_samples <= 8);
1528 i = bcm->noisecalc.nr_samples;
1529 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1530 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1531 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1532 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1533 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1534 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1535 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1536 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1537 bcm->noisecalc.nr_samples++;
1538 if (bcm->noisecalc.nr_samples == 8) {
1539 /* Calculate the Link Quality by the noise samples. */
1540 average = 0;
1541 for (i = 0; i < 8; i++) {
1542 for (j = 0; j < 4; j++)
1543 average += bcm->noisecalc.samples[i][j];
1544 }
1545 average /= (8 * 4);
1546 average *= 125;
1547 average += 64;
1548 average /= 128;
Michael Buesch72fb8512006-03-22 18:10:19 +01001549
John W. Linvillef2223132006-01-23 16:59:58 -05001550 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1551 tmp = (tmp / 128) & 0x1F;
1552 if (tmp >= 8)
1553 average += 2;
1554 else
1555 average -= 25;
1556 if (tmp == 8)
1557 average -= 72;
1558 else
1559 average -= 48;
1560
Michael Buesch72fb8512006-03-22 18:10:19 +01001561/* FIXME: This is wrong, but people want fancy stats. well... */
1562bcm->stats.noise = average;
John W. Linvillef2223132006-01-23 16:59:58 -05001563 if (average > -65)
1564 bcm->stats.link_quality = 0;
1565 else if (average > -75)
1566 bcm->stats.link_quality = 1;
1567 else if (average > -85)
1568 bcm->stats.link_quality = 2;
1569 else
1570 bcm->stats.link_quality = 3;
1571// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1572drop_calculation:
1573 bcm->noisecalc.calculation_running = 0;
1574 return;
1575 }
1576generate_new:
1577 bcm43xx_generate_noise_sample(bcm);
1578}
1579
Michael Buesch489423c2006-02-13 00:11:07 +01001580static void handle_irq_ps(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001581{
1582 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1583 ///TODO: PS TBTT
1584 } else {
1585 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1586 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1587 }
1588 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1589 bcm->reg124_set_0x4 = 1;
1590 //FIXME else set to false?
1591}
1592
Michael Buesch489423c2006-02-13 00:11:07 +01001593static void handle_irq_reg124(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001594{
1595 if (!bcm->reg124_set_0x4)
1596 return;
1597 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1598 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1599 | 0x4);
1600 //FIXME: reset reg124_set_0x4 to false?
1601}
1602
Michael Buesch489423c2006-02-13 00:11:07 +01001603static void handle_irq_pmq(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001604{
1605 u32 tmp;
1606
1607 //TODO: AP mode.
1608
1609 while (1) {
1610 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1611 if (!(tmp & 0x00000008))
1612 break;
1613 }
1614 /* 16bit write is odd, but correct. */
1615 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1616}
1617
1618static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1619 u16 ram_offset, u16 shm_size_offset)
1620{
1621 u32 value;
1622 u16 size = 0;
1623
1624 /* Timestamp. */
1625 //FIXME: assumption: The chip sets the timestamp
1626 value = 0;
1627 bcm43xx_ram_write(bcm, ram_offset++, value);
1628 bcm43xx_ram_write(bcm, ram_offset++, value);
1629 size += 8;
1630
1631 /* Beacon Interval / Capability Information */
1632 value = 0x0000;//FIXME: Which interval?
1633 value |= (1 << 0) << 16; /* ESS */
1634 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1635 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1636 if (!bcm->ieee->open_wep)
1637 value |= (1 << 4) << 16; /* Privacy */
1638 bcm43xx_ram_write(bcm, ram_offset++, value);
1639 size += 4;
1640
1641 /* SSID */
1642 //TODO
1643
1644 /* FH Parameter Set */
1645 //TODO
1646
1647 /* DS Parameter Set */
1648 //TODO
1649
1650 /* CF Parameter Set */
1651 //TODO
1652
1653 /* TIM */
1654 //TODO
1655
1656 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1657}
1658
Michael Buesch489423c2006-02-13 00:11:07 +01001659static void handle_irq_beacon(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001660{
1661 u32 status;
1662
1663 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1664 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1665
1666 if ((status & 0x1) && (status & 0x2)) {
1667 /* ACK beacon IRQ. */
1668 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1669 BCM43xx_IRQ_BEACON);
1670 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1671 return;
1672 }
1673 if (!(status & 0x1)) {
1674 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
1675 status |= 0x1;
1676 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1677 }
1678 if (!(status & 0x2)) {
1679 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
1680 status |= 0x2;
1681 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1682 }
1683}
1684
John W. Linvillef2223132006-01-23 16:59:58 -05001685/* Interrupt handler bottom-half */
1686static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
1687{
1688 u32 reason;
1689 u32 dma_reason[4];
1690 int activity = 0;
1691 unsigned long flags;
1692
1693#ifdef CONFIG_BCM43XX_DEBUG
1694 u32 _handled = 0x00000000;
1695# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
1696#else
1697# define bcmirq_handled(irq) do { /* nothing */ } while (0)
1698#endif /* CONFIG_BCM43XX_DEBUG*/
1699
Michael Bueschefccb642006-03-11 13:39:14 +01001700 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001701 reason = bcm->irq_reason;
1702 dma_reason[0] = bcm->dma_reason[0];
1703 dma_reason[1] = bcm->dma_reason[1];
1704 dma_reason[2] = bcm->dma_reason[2];
1705 dma_reason[3] = bcm->dma_reason[3];
1706
1707 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
1708 /* TX error. We get this when Template Ram is written in wrong endianess
1709 * in dummy_tx(). We also get this if something is wrong with the TX header
1710 * on DMA or PIO queues.
1711 * Maybe we get this in other error conditions, too.
1712 */
Michael Buesch73733842006-03-12 19:44:29 +01001713 printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
John W. Linvillef2223132006-01-23 16:59:58 -05001714 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
1715 }
Michael Buesch73733842006-03-12 19:44:29 +01001716 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
1717 (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
1718 (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
1719 (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
1720 printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
1721 "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1722 dma_reason[0], dma_reason[1],
1723 dma_reason[2], dma_reason[3]);
1724 bcm43xx_controller_restart(bcm, "DMA error");
1725 bcm43xx_unlock_mmio(bcm, flags);
1726 return;
1727 }
1728 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
1729 (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
1730 (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
1731 (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
1732 printkl(KERN_ERR PFX "DMA error: "
1733 "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1734 dma_reason[0], dma_reason[1],
1735 dma_reason[2], dma_reason[3]);
1736 }
John W. Linvillef2223132006-01-23 16:59:58 -05001737
1738 if (reason & BCM43xx_IRQ_PS) {
1739 handle_irq_ps(bcm);
1740 bcmirq_handled(BCM43xx_IRQ_PS);
1741 }
1742
1743 if (reason & BCM43xx_IRQ_REG124) {
1744 handle_irq_reg124(bcm);
1745 bcmirq_handled(BCM43xx_IRQ_REG124);
1746 }
1747
1748 if (reason & BCM43xx_IRQ_BEACON) {
1749 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
1750 handle_irq_beacon(bcm);
1751 bcmirq_handled(BCM43xx_IRQ_BEACON);
1752 }
1753
1754 if (reason & BCM43xx_IRQ_PMQ) {
1755 handle_irq_pmq(bcm);
1756 bcmirq_handled(BCM43xx_IRQ_PMQ);
1757 }
1758
1759 if (reason & BCM43xx_IRQ_SCAN) {
1760 /*TODO*/
1761 //bcmirq_handled(BCM43xx_IRQ_SCAN);
1762 }
1763
1764 if (reason & BCM43xx_IRQ_NOISE) {
1765 handle_irq_noise(bcm);
1766 bcmirq_handled(BCM43xx_IRQ_NOISE);
1767 }
1768
1769 /* Check the DMA reason registers for received data. */
1770 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
1771 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
1772 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001773 if (bcm43xx_using_pio(bcm))
Michael Buesche9357c02006-03-13 19:27:34 +01001774 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
John W. Linvillef2223132006-01-23 16:59:58 -05001775 else
Michael Buesche9357c02006-03-13 19:27:34 +01001776 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
Michael Bueschdcfd7202006-02-12 20:25:55 +01001777 /* We intentionally don't set "activity" to 1, here. */
John W. Linvillef2223132006-01-23 16:59:58 -05001778 }
1779 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesche1b1b582006-03-13 15:20:05 +01001780 if (bcm43xx_using_pio(bcm))
Michael Buesche9357c02006-03-13 19:27:34 +01001781 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
Michael Buesche1b1b582006-03-13 15:20:05 +01001782 else
Michael Buesche9357c02006-03-13 19:27:34 +01001783 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
Michael Buesche1b1b582006-03-13 15:20:05 +01001784 activity = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001785 }
1786 bcmirq_handled(BCM43xx_IRQ_RX);
1787
1788 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
Michael Buesche1b1b582006-03-13 15:20:05 +01001789 handle_irq_transmit_status(bcm);
1790 activity = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001791 //TODO: In AP mode, this also causes sending of powersave responses.
1792 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
1793 }
1794
John W. Linvillef2223132006-01-23 16:59:58 -05001795 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
1796 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
1797#ifdef CONFIG_BCM43XX_DEBUG
1798 if (unlikely(reason & ~_handled)) {
1799 printkl(KERN_WARNING PFX
1800 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
1801 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1802 reason, (reason & ~_handled),
1803 dma_reason[0], dma_reason[1],
1804 dma_reason[2], dma_reason[3]);
1805 }
1806#endif
1807#undef bcmirq_handled
1808
1809 if (!modparam_noleds)
1810 bcm43xx_leds_update(bcm, activity);
1811 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
Michael Bueschefccb642006-03-11 13:39:14 +01001812 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001813}
1814
Michael Buesch0ac59da2006-03-19 21:43:40 +01001815static void pio_irq_workaround(struct bcm43xx_private *bcm,
1816 u16 base, int queueidx)
John W. Linvillef2223132006-01-23 16:59:58 -05001817{
Michael Buesch0ac59da2006-03-19 21:43:40 +01001818 u16 rxctl;
John W. Linvillef2223132006-01-23 16:59:58 -05001819
Michael Buesch0ac59da2006-03-19 21:43:40 +01001820 rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);
1821 if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)
1822 bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;
1823 else
1824 bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;
1825}
1826
1827static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
1828{
Michael Buesch77db31e2006-02-12 16:47:44 +01001829 if (bcm43xx_using_pio(bcm) &&
John W. Linvillef2223132006-01-23 16:59:58 -05001830 (bcm->current_core->rev < 3) &&
1831 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
1832 /* Apply a PIO specific workaround to the dma_reasons */
Michael Buesch0ac59da2006-03-19 21:43:40 +01001833 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);
1834 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);
1835 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);
1836 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);
John W. Linvillef2223132006-01-23 16:59:58 -05001837 }
1838
Michael Buesch0ac59da2006-03-19 21:43:40 +01001839 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
John W. Linvillef2223132006-01-23 16:59:58 -05001840
1841 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
1842 bcm->dma_reason[0]);
1843 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
1844 bcm->dma_reason[1]);
1845 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
1846 bcm->dma_reason[2]);
1847 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
1848 bcm->dma_reason[3]);
1849}
1850
1851/* Interrupt handler top-half */
1852static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
1853{
Michael Bueschefccb642006-03-11 13:39:14 +01001854 irqreturn_t ret = IRQ_HANDLED;
John W. Linvillef2223132006-01-23 16:59:58 -05001855 struct bcm43xx_private *bcm = dev_id;
Michael Buesch0ac59da2006-03-19 21:43:40 +01001856 u32 reason;
John W. Linvillef2223132006-01-23 16:59:58 -05001857
1858 if (!bcm)
1859 return IRQ_NONE;
1860
Michael Bueschefccb642006-03-11 13:39:14 +01001861 spin_lock(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001862
1863 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
1864 if (reason == 0xffffffff) {
1865 /* irq not for us (shared irq) */
Michael Bueschefccb642006-03-11 13:39:14 +01001866 ret = IRQ_NONE;
1867 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001868 }
Michael Buesch0ac59da2006-03-19 21:43:40 +01001869 reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
1870 if (!reason)
Michael Bueschefccb642006-03-11 13:39:14 +01001871 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001872
Michael Buesch0ac59da2006-03-19 21:43:40 +01001873 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
1874 & 0x0001dc00;
1875 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
1876 & 0x0000dc00;
1877 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
1878 & 0x0000dc00;
1879 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
1880 & 0x0001dc00;
1881
1882 bcm43xx_interrupt_ack(bcm, reason);
John W. Linvillef2223132006-01-23 16:59:58 -05001883
Michael Bueschbf7b8762006-02-21 17:58:18 +01001884 /* Only accept IRQs, if we are initialized properly.
1885 * This avoids an RX race while initializing.
1886 * We should probably not enable IRQs before we are initialized
1887 * completely, but some careful work is needed to fix this. I think it
1888 * is best to stay with this cheap workaround for now... .
1889 */
1890 if (likely(bcm->initialized)) {
1891 /* disable all IRQs. They are enabled again in the bottom half. */
1892 bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1893 /* save the reason code and call our bottom half. */
1894 bcm->irq_reason = reason;
1895 tasklet_schedule(&bcm->isr_tasklet);
1896 }
John W. Linvillef2223132006-01-23 16:59:58 -05001897
Michael Bueschefccb642006-03-11 13:39:14 +01001898out:
1899 mmiowb();
1900 spin_unlock(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001901
Michael Bueschefccb642006-03-11 13:39:14 +01001902 return ret;
John W. Linvillef2223132006-01-23 16:59:58 -05001903}
1904
Michael Buescha4a600d2006-02-01 22:09:52 +01001905static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
John W. Linvillef2223132006-01-23 16:59:58 -05001906{
Michael Buescha4a600d2006-02-01 22:09:52 +01001907 if (bcm->firmware_norelease && !force)
John W. Linvillef2223132006-01-23 16:59:58 -05001908 return; /* Suspending or controller reset. */
1909 release_firmware(bcm->ucode);
1910 bcm->ucode = NULL;
1911 release_firmware(bcm->pcm);
1912 bcm->pcm = NULL;
1913 release_firmware(bcm->initvals0);
1914 bcm->initvals0 = NULL;
1915 release_firmware(bcm->initvals1);
1916 bcm->initvals1 = NULL;
1917}
1918
1919static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1920{
Michael Buesche9357c02006-03-13 19:27:34 +01001921 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001922 u8 rev = bcm->current_core->rev;
1923 int err = 0;
1924 int nr;
1925 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
1926
1927 if (!bcm->ucode) {
1928 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
1929 (rev >= 5 ? 5 : rev),
1930 modparam_fwpostfix);
1931 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
1932 if (err) {
1933 printk(KERN_ERR PFX
1934 "Error: Microcode \"%s\" not available or load failed.\n",
1935 buf);
1936 goto error;
1937 }
1938 }
1939
1940 if (!bcm->pcm) {
1941 snprintf(buf, ARRAY_SIZE(buf),
1942 "bcm43xx_pcm%d%s.fw",
1943 (rev < 5 ? 4 : 5),
1944 modparam_fwpostfix);
1945 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
1946 if (err) {
1947 printk(KERN_ERR PFX
1948 "Error: PCM \"%s\" not available or load failed.\n",
1949 buf);
1950 goto error;
1951 }
1952 }
1953
1954 if (!bcm->initvals0) {
1955 if (rev == 2 || rev == 4) {
1956 switch (phy->type) {
1957 case BCM43xx_PHYTYPE_A:
1958 nr = 3;
1959 break;
1960 case BCM43xx_PHYTYPE_B:
1961 case BCM43xx_PHYTYPE_G:
1962 nr = 1;
1963 break;
1964 default:
1965 goto err_noinitval;
1966 }
1967
1968 } else if (rev >= 5) {
1969 switch (phy->type) {
1970 case BCM43xx_PHYTYPE_A:
1971 nr = 7;
1972 break;
1973 case BCM43xx_PHYTYPE_B:
1974 case BCM43xx_PHYTYPE_G:
1975 nr = 5;
1976 break;
1977 default:
1978 goto err_noinitval;
1979 }
1980 } else
1981 goto err_noinitval;
1982 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1983 nr, modparam_fwpostfix);
1984
1985 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
1986 if (err) {
1987 printk(KERN_ERR PFX
1988 "Error: InitVals \"%s\" not available or load failed.\n",
1989 buf);
1990 goto error;
1991 }
1992 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
1993 printk(KERN_ERR PFX "InitVals fileformat error.\n");
1994 goto error;
1995 }
1996 }
1997
1998 if (!bcm->initvals1) {
1999 if (rev >= 5) {
2000 u32 sbtmstatehigh;
2001
2002 switch (phy->type) {
2003 case BCM43xx_PHYTYPE_A:
2004 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
2005 if (sbtmstatehigh & 0x00010000)
2006 nr = 9;
2007 else
2008 nr = 10;
2009 break;
2010 case BCM43xx_PHYTYPE_B:
2011 case BCM43xx_PHYTYPE_G:
2012 nr = 6;
2013 break;
2014 default:
2015 goto err_noinitval;
2016 }
2017 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2018 nr, modparam_fwpostfix);
2019
2020 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
2021 if (err) {
2022 printk(KERN_ERR PFX
2023 "Error: InitVals \"%s\" not available or load failed.\n",
2024 buf);
2025 goto error;
2026 }
2027 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
2028 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2029 goto error;
2030 }
2031 }
2032 }
2033
2034out:
2035 return err;
2036error:
Michael Buescha4a600d2006-02-01 22:09:52 +01002037 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002038 goto out;
2039err_noinitval:
2040 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2041 err = -ENOENT;
2042 goto error;
2043}
2044
2045static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2046{
2047 const u32 *data;
2048 unsigned int i, len;
2049
John W. Linvillef2223132006-01-23 16:59:58 -05002050 /* Upload Microcode. */
2051 data = (u32 *)(bcm->ucode->data);
2052 len = bcm->ucode->size / sizeof(u32);
2053 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2054 for (i = 0; i < len; i++) {
2055 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2056 be32_to_cpu(data[i]));
2057 udelay(10);
2058 }
2059
2060 /* Upload PCM data. */
2061 data = (u32 *)(bcm->pcm->data);
2062 len = bcm->pcm->size / sizeof(u32);
2063 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2064 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2065 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2066 for (i = 0; i < len; i++) {
2067 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2068 be32_to_cpu(data[i]));
2069 udelay(10);
2070 }
John W. Linvillef2223132006-01-23 16:59:58 -05002071}
2072
Michael Buescha4a600d2006-02-01 22:09:52 +01002073static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2074 const struct bcm43xx_initval *data,
2075 const unsigned int len)
John W. Linvillef2223132006-01-23 16:59:58 -05002076{
2077 u16 offset, size;
2078 u32 value;
2079 unsigned int i;
2080
2081 for (i = 0; i < len; i++) {
2082 offset = be16_to_cpu(data[i].offset);
2083 size = be16_to_cpu(data[i].size);
2084 value = be32_to_cpu(data[i].value);
2085
Michael Buescha4a600d2006-02-01 22:09:52 +01002086 if (unlikely(offset >= 0x1000))
2087 goto err_format;
2088 if (size == 2) {
2089 if (unlikely(value & 0xFFFF0000))
2090 goto err_format;
2091 bcm43xx_write16(bcm, offset, (u16)value);
2092 } else if (size == 4) {
John W. Linvillef2223132006-01-23 16:59:58 -05002093 bcm43xx_write32(bcm, offset, value);
Michael Buescha4a600d2006-02-01 22:09:52 +01002094 } else
2095 goto err_format;
John W. Linvillef2223132006-01-23 16:59:58 -05002096 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002097
2098 return 0;
2099
2100err_format:
2101 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2102 "Please fix your bcm43xx firmware files.\n");
2103 return -EPROTO;
John W. Linvillef2223132006-01-23 16:59:58 -05002104}
2105
Michael Buescha4a600d2006-02-01 22:09:52 +01002106static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002107{
Michael Buescha4a600d2006-02-01 22:09:52 +01002108 int err;
2109
Michael Buescha4a600d2006-02-01 22:09:52 +01002110 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2111 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2112 if (err)
2113 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002114 if (bcm->initvals1) {
Michael Buescha4a600d2006-02-01 22:09:52 +01002115 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2116 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2117 if (err)
2118 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002119 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002120out:
Michael Buescha4a600d2006-02-01 22:09:52 +01002121 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002122}
2123
2124static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2125{
2126 int res;
2127 unsigned int i;
2128 u32 data;
2129
2130 bcm->irq = bcm->pci_dev->irq;
2131#ifdef CONFIG_BCM947XX
2132 if (bcm->pci_dev->bus->number == 0) {
2133 struct pci_dev *d = NULL;
2134 /* FIXME: we will probably need more device IDs here... */
2135 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2136 if (d != NULL) {
2137 bcm->irq = d->irq;
2138 }
2139 }
2140#endif
2141 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
Michael Buesch65f3f192006-01-31 20:11:38 +01002142 SA_SHIRQ, KBUILD_MODNAME, bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002143 if (res) {
2144 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
Michael Buesch489423c2006-02-13 00:11:07 +01002145 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002146 }
2147 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2148 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2149 i = 0;
2150 while (1) {
2151 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2152 if (data == BCM43xx_IRQ_READY)
2153 break;
2154 i++;
2155 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2156 printk(KERN_ERR PFX "Card IRQ register not responding. "
2157 "Giving up.\n");
2158 free_irq(bcm->irq, bcm);
2159 return -ENODEV;
2160 }
2161 udelay(10);
2162 }
2163 // dummy read
2164 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2165
2166 return 0;
2167}
2168
2169/* Switch to the core used to write the GPIO register.
2170 * This is either the ChipCommon, or the PCI core.
2171 */
Michael Buesch489423c2006-02-13 00:11:07 +01002172static int switch_to_gpio_core(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002173{
2174 int err;
2175
2176 /* Where to find the GPIO register depends on the chipset.
2177 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2178 * control register. Otherwise the register at offset 0x6c in the
2179 * PCI core is the GPIO control register.
2180 */
2181 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2182 if (err == -ENODEV) {
2183 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
Michael Buesch489423c2006-02-13 00:11:07 +01002184 if (unlikely(err == -ENODEV)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002185 printk(KERN_ERR PFX "gpio error: "
2186 "Neither ChipCommon nor PCI core available!\n");
Michael Buesch714eece2006-03-18 21:28:46 +01002187 }
2188 }
John W. Linvillef2223132006-01-23 16:59:58 -05002189
Michael Buesch714eece2006-03-18 21:28:46 +01002190 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002191}
2192
2193/* Initialize the GPIOs
2194 * http://bcm-specs.sipsolutions.net/GPIO
2195 */
2196static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2197{
2198 struct bcm43xx_coreinfo *old_core;
2199 int err;
Michael Buesch714eece2006-03-18 21:28:46 +01002200 u32 mask, set;
John W. Linvillef2223132006-01-23 16:59:58 -05002201
Michael Buesch714eece2006-03-18 21:28:46 +01002202 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2203 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2204 & 0xFFFF3FFF);
John W. Linvillef2223132006-01-23 16:59:58 -05002205
Michael Buesch714eece2006-03-18 21:28:46 +01002206 bcm43xx_leds_switch_all(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002207 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2208 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2209
Michael Buesch714eece2006-03-18 21:28:46 +01002210 mask = 0x0000001F;
2211 set = 0x0000000F;
John W. Linvillef2223132006-01-23 16:59:58 -05002212 if (bcm->chip_id == 0x4301) {
Michael Buesch714eece2006-03-18 21:28:46 +01002213 mask |= 0x0060;
2214 set |= 0x0060;
2215 }
2216 if (0 /* FIXME: conditional unknown */) {
2217 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2218 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2219 | 0x0100);
2220 mask |= 0x0180;
2221 set |= 0x0180;
John W. Linvillef2223132006-01-23 16:59:58 -05002222 }
2223 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
Michael Buesch714eece2006-03-18 21:28:46 +01002224 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2225 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2226 | 0x0200);
2227 mask |= 0x0200;
2228 set |= 0x0200;
John W. Linvillef2223132006-01-23 16:59:58 -05002229 }
Michael Buesch714eece2006-03-18 21:28:46 +01002230 if (bcm->current_core->rev >= 2)
2231 mask |= 0x0010; /* FIXME: This is redundant. */
John W. Linvillef2223132006-01-23 16:59:58 -05002232
Michael Buesch714eece2006-03-18 21:28:46 +01002233 old_core = bcm->current_core;
2234 err = switch_to_gpio_core(bcm);
2235 if (err)
2236 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002237 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
Michael Buesch714eece2006-03-18 21:28:46 +01002238 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);
John W. Linvillef2223132006-01-23 16:59:58 -05002239 err = bcm43xx_switch_core(bcm, old_core);
Michael Buesch714eece2006-03-18 21:28:46 +01002240out:
2241 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002242}
2243
2244/* Turn off all GPIO stuff. Call this on module unload, for example. */
2245static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2246{
2247 struct bcm43xx_coreinfo *old_core;
2248 int err;
2249
2250 old_core = bcm->current_core;
2251 err = switch_to_gpio_core(bcm);
2252 if (err)
2253 return err;
2254 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2255 err = bcm43xx_switch_core(bcm, old_core);
2256 assert(err == 0);
2257
2258 return 0;
2259}
2260
2261/* http://bcm-specs.sipsolutions.net/EnableMac */
2262void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2263{
2264 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2265 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2266 | BCM43xx_SBF_MAC_ENABLED);
2267 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2268 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2269 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2270 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2271}
2272
2273/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2274void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2275{
2276 int i;
2277 u32 tmp;
2278
2279 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2280 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2281 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2282 & ~BCM43xx_SBF_MAC_ENABLED);
2283 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
Michael Buesch921e4852006-02-08 17:55:55 +01002284 for (i = 100000; i; i--) {
John W. Linvillef2223132006-01-23 16:59:58 -05002285 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch921e4852006-02-08 17:55:55 +01002286 if (tmp & BCM43xx_IRQ_READY)
2287 return;
John W. Linvillef2223132006-01-23 16:59:58 -05002288 udelay(10);
2289 }
Michael Buesch921e4852006-02-08 17:55:55 +01002290 printkl(KERN_ERR PFX "MAC suspend failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05002291}
2292
2293void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2294 int iw_mode)
2295{
2296 unsigned long flags;
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002297 struct net_device *net_dev = bcm->net_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05002298 u32 status;
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002299 u16 value;
John W. Linvillef2223132006-01-23 16:59:58 -05002300
2301 spin_lock_irqsave(&bcm->ieee->lock, flags);
2302 bcm->ieee->iw_mode = iw_mode;
2303 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2304 if (iw_mode == IW_MODE_MONITOR)
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002305 net_dev->type = ARPHRD_IEEE80211;
John W. Linvillef2223132006-01-23 16:59:58 -05002306 else
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002307 net_dev->type = ARPHRD_ETHER;
John W. Linvillef2223132006-01-23 16:59:58 -05002308
John W. Linvillef2223132006-01-23 16:59:58 -05002309 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2310 /* Reset status to infrastructured mode */
2311 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002312 status &= ~BCM43xx_SBF_MODE_PROMISC;
2313 status |= BCM43xx_SBF_MODE_NOTADHOC;
2314
2315/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */
2316status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002317
2318 switch (iw_mode) {
2319 case IW_MODE_MONITOR:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002320 status |= BCM43xx_SBF_MODE_MONITOR;
2321 status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002322 break;
2323 case IW_MODE_ADHOC:
2324 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2325 break;
2326 case IW_MODE_MASTER:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002327 status |= BCM43xx_SBF_MODE_AP;
2328 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002329 case IW_MODE_SECOND:
2330 case IW_MODE_REPEAT:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002331 TODO(); /* TODO */
John W. Linvillef2223132006-01-23 16:59:58 -05002332 break;
2333 case IW_MODE_INFRA:
2334 /* nothing to be done here... */
2335 break;
2336 default:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002337 dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);
John W. Linvillef2223132006-01-23 16:59:58 -05002338 }
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002339 if (net_dev->flags & IFF_PROMISC)
2340 status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002341 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002342
2343 value = 0x0002;
2344 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2345 if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
2346 value = 0x0064;
2347 else
2348 value = 0x0032;
2349 }
2350 bcm43xx_write16(bcm, 0x0612, value);
John W. Linvillef2223132006-01-23 16:59:58 -05002351}
2352
2353/* This is the opposite of bcm43xx_chip_init() */
2354static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2355{
2356 bcm43xx_radio_turn_off(bcm);
2357 if (!modparam_noleds)
2358 bcm43xx_leds_exit(bcm);
2359 bcm43xx_gpio_cleanup(bcm);
2360 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002361 bcm43xx_release_firmware(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002362}
2363
2364/* Initialize the chip
2365 * http://bcm-specs.sipsolutions.net/ChipInit
2366 */
2367static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2368{
Michael Buesche9357c02006-03-13 19:27:34 +01002369 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
2370 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002371 int err;
John W. Linvillef2223132006-01-23 16:59:58 -05002372 int tmp;
2373 u32 value32;
2374 u16 value16;
2375
2376 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2377 BCM43xx_SBF_CORE_READY
2378 | BCM43xx_SBF_400);
2379
2380 err = bcm43xx_request_firmware(bcm);
2381 if (err)
2382 goto out;
2383 bcm43xx_upload_microcode(bcm);
2384
2385 err = bcm43xx_initialize_irq(bcm);
2386 if (err)
Michael Buescha4a600d2006-02-01 22:09:52 +01002387 goto err_release_fw;
John W. Linvillef2223132006-01-23 16:59:58 -05002388
2389 err = bcm43xx_gpio_init(bcm);
2390 if (err)
2391 goto err_free_irq;
2392
Michael Buescha4a600d2006-02-01 22:09:52 +01002393 err = bcm43xx_upload_initvals(bcm);
2394 if (err)
2395 goto err_gpio_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002396 bcm43xx_radio_turn_on(bcm);
2397
John W. Linvillef2223132006-01-23 16:59:58 -05002398 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2399 err = bcm43xx_phy_init(bcm);
2400 if (err)
2401 goto err_radio_off;
2402
2403 /* Select initial Interference Mitigation. */
Michael Buesche9357c02006-03-13 19:27:34 +01002404 tmp = radio->interfmode;
2405 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
John W. Linvillef2223132006-01-23 16:59:58 -05002406 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2407
2408 bcm43xx_phy_set_antenna_diversity(bcm);
2409 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
Michael Buesche9357c02006-03-13 19:27:34 +01002410 if (phy->type == BCM43xx_PHYTYPE_B) {
John W. Linvillef2223132006-01-23 16:59:58 -05002411 value16 = bcm43xx_read16(bcm, 0x005E);
2412 value16 |= 0x0004;
2413 bcm43xx_write16(bcm, 0x005E, value16);
2414 }
2415 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2416 if (bcm->current_core->rev < 5)
2417 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2418
2419 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2420 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2421 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2422 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2423 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2424 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
John W. Linvillef2223132006-01-23 16:59:58 -05002425
John W. Linvillef2223132006-01-23 16:59:58 -05002426 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002427 value32 |= 0x100000;
John W. Linvillef2223132006-01-23 16:59:58 -05002428 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2429
Michael Buesch77db31e2006-02-12 16:47:44 +01002430 if (bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002431 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2432 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2433 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2434 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2435 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2436 }
2437
2438 /* Probe Response Timeout value */
2439 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2440 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2441
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002442 /* Initially set the wireless operation mode. */
2443 bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode);
John W. Linvillef2223132006-01-23 16:59:58 -05002444
2445 if (bcm->current_core->rev < 3) {
2446 bcm43xx_write16(bcm, 0x060E, 0x0000);
2447 bcm43xx_write16(bcm, 0x0610, 0x8000);
2448 bcm43xx_write16(bcm, 0x0604, 0x0000);
2449 bcm43xx_write16(bcm, 0x0606, 0x0200);
2450 } else {
2451 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2452 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2453 }
2454 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2455 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2456 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2457 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2458 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2459
2460 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2461 value32 |= 0x00100000;
2462 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2463
2464 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2465
2466 assert(err == 0);
2467 dprintk(KERN_INFO PFX "Chip initialized\n");
2468out:
2469 return err;
2470
2471err_radio_off:
2472 bcm43xx_radio_turn_off(bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002473err_gpio_cleanup:
John W. Linvillef2223132006-01-23 16:59:58 -05002474 bcm43xx_gpio_cleanup(bcm);
2475err_free_irq:
2476 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002477err_release_fw:
2478 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002479 goto out;
2480}
2481
2482/* Validate chip access
2483 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2484static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2485{
John W. Linvillef2223132006-01-23 16:59:58 -05002486 u32 value;
2487 u32 shm_backup;
2488
2489 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2490 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
Michael Buesch489423c2006-02-13 00:11:07 +01002491 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2492 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002493 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
Michael Buesch489423c2006-02-13 00:11:07 +01002494 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2495 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002496 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2497
2498 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch489423c2006-02-13 00:11:07 +01002499 if ((value | 0x80000000) != 0x80000400)
2500 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002501
2502 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch489423c2006-02-13 00:11:07 +01002503 if (value != 0x00000000)
2504 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002505
Michael Buesch489423c2006-02-13 00:11:07 +01002506 return 0;
2507error:
2508 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2509 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002510}
2511
Michael Buesch8afceb12006-03-25 17:04:41 +01002512static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
Michael Buesche9357c02006-03-13 19:27:34 +01002513{
2514 /* Initialize a "phyinfo" structure. The structure is already
2515 * zeroed out.
2516 */
2517 phy->antenna_diversity = 0xFFFF;
2518 phy->savedpctlreg = 0xFFFF;
2519 phy->minlowsig[0] = 0xFFFF;
2520 phy->minlowsig[1] = 0xFFFF;
2521 spin_lock_init(&phy->lock);
2522}
2523
Michael Buesch8afceb12006-03-25 17:04:41 +01002524static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
Michael Buesche9357c02006-03-13 19:27:34 +01002525{
2526 /* Initialize a "radioinfo" structure. The structure is already
2527 * zeroed out.
2528 */
2529 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2530 radio->channel = 0xFF;
2531 radio->initial_channel = 0xFF;
2532 radio->lofcal = 0xFFFF;
2533 radio->initval = 0xFFFF;
2534 radio->nrssi[0] = -1000;
2535 radio->nrssi[1] = -1000;
2536}
2537
John W. Linvillef2223132006-01-23 16:59:58 -05002538static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2539{
2540 int err, i;
2541 int current_core;
2542 u32 core_vendor, core_id, core_rev;
2543 u32 sb_id_hi, chip_id_32 = 0;
2544 u16 pci_device, chip_id_16;
2545 u8 core_count;
2546
2547 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2548 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
John W. Linvillef2223132006-01-23 16:59:58 -05002549 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2550 * BCM43xx_MAX_80211_CORES);
Michael Buesche9357c02006-03-13 19:27:34 +01002551 memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
2552 * BCM43xx_MAX_80211_CORES);
2553 bcm->current_80211_core_idx = -1;
2554 bcm->nr_80211_available = 0;
2555 bcm->current_core = NULL;
2556 bcm->active_80211_core = NULL;
John W. Linvillef2223132006-01-23 16:59:58 -05002557
2558 /* map core 0 */
2559 err = _switch_core(bcm, 0);
2560 if (err)
2561 goto out;
2562
2563 /* fetch sb_id_hi from core information registers */
2564 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2565
2566 core_id = (sb_id_hi & 0xFFF0) >> 4;
2567 core_rev = (sb_id_hi & 0xF);
2568 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2569
2570 /* if present, chipcommon is always core 0; read the chipid from it */
2571 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2572 chip_id_32 = bcm43xx_read32(bcm, 0);
2573 chip_id_16 = chip_id_32 & 0xFFFF;
Michael Buesche9357c02006-03-13 19:27:34 +01002574 bcm->core_chipcommon.available = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002575 bcm->core_chipcommon.id = core_id;
2576 bcm->core_chipcommon.rev = core_rev;
2577 bcm->core_chipcommon.index = 0;
2578 /* While we are at it, also read the capabilities. */
2579 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2580 } else {
2581 /* without a chipCommon, use a hard coded table. */
2582 pci_device = bcm->pci_dev->device;
2583 if (pci_device == 0x4301)
2584 chip_id_16 = 0x4301;
2585 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2586 chip_id_16 = 0x4307;
2587 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2588 chip_id_16 = 0x4402;
2589 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2590 chip_id_16 = 0x4610;
2591 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2592 chip_id_16 = 0x4710;
2593#ifdef CONFIG_BCM947XX
2594 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2595 chip_id_16 = 0x4309;
2596#endif
2597 else {
2598 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2599 return -ENODEV;
2600 }
2601 }
2602
2603 /* ChipCommon with Core Rev >=4 encodes number of cores,
2604 * otherwise consult hardcoded table */
2605 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2606 core_count = (chip_id_32 & 0x0F000000) >> 24;
2607 } else {
2608 switch (chip_id_16) {
2609 case 0x4610:
2610 case 0x4704:
2611 case 0x4710:
2612 core_count = 9;
2613 break;
2614 case 0x4310:
2615 core_count = 8;
2616 break;
2617 case 0x5365:
2618 core_count = 7;
2619 break;
2620 case 0x4306:
2621 core_count = 6;
2622 break;
2623 case 0x4301:
2624 case 0x4307:
2625 core_count = 5;
2626 break;
2627 case 0x4402:
2628 core_count = 3;
2629 break;
2630 default:
2631 /* SOL if we get here */
2632 assert(0);
2633 core_count = 1;
2634 }
2635 }
2636
2637 bcm->chip_id = chip_id_16;
2638 bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16;
2639
2640 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2641 bcm->chip_id, bcm->chip_rev);
2642 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
Michael Buesche9357c02006-03-13 19:27:34 +01002643 if (bcm->core_chipcommon.available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002644 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2645 core_id, core_rev, core_vendor,
2646 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2647 }
2648
Michael Buesche9357c02006-03-13 19:27:34 +01002649 if (bcm->core_chipcommon.available)
John W. Linvillef2223132006-01-23 16:59:58 -05002650 current_core = 1;
2651 else
2652 current_core = 0;
2653 for ( ; current_core < core_count; current_core++) {
2654 struct bcm43xx_coreinfo *core;
Michael Buesche9357c02006-03-13 19:27:34 +01002655 struct bcm43xx_coreinfo_80211 *ext_80211;
John W. Linvillef2223132006-01-23 16:59:58 -05002656
2657 err = _switch_core(bcm, current_core);
2658 if (err)
2659 goto out;
2660 /* Gather information */
2661 /* fetch sb_id_hi from core information registers */
2662 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2663
2664 /* extract core_id, core_rev, core_vendor */
2665 core_id = (sb_id_hi & 0xFFF0) >> 4;
2666 core_rev = (sb_id_hi & 0xF);
2667 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2668
2669 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2670 current_core, core_id, core_rev, core_vendor,
2671 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2672
2673 core = NULL;
2674 switch (core_id) {
2675 case BCM43xx_COREID_PCI:
2676 core = &bcm->core_pci;
Michael Buesche9357c02006-03-13 19:27:34 +01002677 if (core->available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002678 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2679 continue;
2680 }
2681 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002682 case BCM43xx_COREID_80211:
2683 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2684 core = &(bcm->core_80211[i]);
Michael Buesche9357c02006-03-13 19:27:34 +01002685 ext_80211 = &(bcm->core_80211_ext[i]);
2686 if (!core->available)
John W. Linvillef2223132006-01-23 16:59:58 -05002687 break;
2688 core = NULL;
2689 }
2690 if (!core) {
2691 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2692 BCM43xx_MAX_80211_CORES);
2693 continue;
2694 }
2695 if (i != 0) {
2696 /* More than one 80211 core is only supported
2697 * by special chips.
2698 * There are chips with two 80211 cores, but with
2699 * dangling pins on the second core. Be careful
2700 * and ignore these cores here.
2701 */
2702 if (bcm->pci_dev->device != 0x4324) {
2703 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2704 continue;
2705 }
2706 }
2707 switch (core_rev) {
2708 case 2:
2709 case 4:
2710 case 5:
2711 case 6:
2712 case 7:
2713 case 9:
2714 break;
2715 default:
2716 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2717 core_rev);
2718 err = -ENODEV;
2719 goto out;
2720 }
Michael Buesche9357c02006-03-13 19:27:34 +01002721 bcm->nr_80211_available++;
2722 bcm43xx_init_struct_phyinfo(&ext_80211->phy);
2723 bcm43xx_init_struct_radioinfo(&ext_80211->radio);
John W. Linvillef2223132006-01-23 16:59:58 -05002724 break;
2725 case BCM43xx_COREID_CHIPCOMMON:
2726 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2727 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002728 }
2729 if (core) {
Michael Buesche9357c02006-03-13 19:27:34 +01002730 core->available = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002731 core->id = core_id;
2732 core->rev = core_rev;
2733 core->index = current_core;
2734 }
2735 }
2736
Michael Buesche9357c02006-03-13 19:27:34 +01002737 if (!bcm->core_80211[0].available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002738 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2739 err = -ENODEV;
2740 goto out;
2741 }
2742
2743 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2744
2745 assert(err == 0);
2746out:
2747 return err;
2748}
2749
2750static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2751{
2752 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2753 u8 *bssid = bcm->ieee->bssid;
2754
2755 switch (bcm->ieee->iw_mode) {
2756 case IW_MODE_ADHOC:
2757 random_ether_addr(bssid);
2758 break;
2759 case IW_MODE_MASTER:
2760 case IW_MODE_INFRA:
2761 case IW_MODE_REPEAT:
2762 case IW_MODE_SECOND:
2763 case IW_MODE_MONITOR:
2764 memcpy(bssid, mac, ETH_ALEN);
2765 break;
2766 default:
2767 assert(0);
2768 }
2769}
2770
2771static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
2772 u16 rate,
2773 int is_ofdm)
2774{
2775 u16 offset;
2776
2777 if (is_ofdm) {
2778 offset = 0x480;
2779 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2780 }
2781 else {
2782 offset = 0x4C0;
2783 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2784 }
2785 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
2786 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
2787}
2788
2789static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
2790{
Michael Buesche9357c02006-03-13 19:27:34 +01002791 switch (bcm43xx_current_phy(bcm)->type) {
John W. Linvillef2223132006-01-23 16:59:58 -05002792 case BCM43xx_PHYTYPE_A:
2793 case BCM43xx_PHYTYPE_G:
2794 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
2795 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
2796 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
2797 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
2798 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
2799 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
2800 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
2801 case BCM43xx_PHYTYPE_B:
2802 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
2803 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
2804 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
2805 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
2806 break;
2807 default:
2808 assert(0);
2809 }
2810}
2811
2812static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2813{
2814 bcm43xx_chip_cleanup(bcm);
2815 bcm43xx_pio_free(bcm);
2816 bcm43xx_dma_free(bcm);
2817
Michael Buesche9357c02006-03-13 19:27:34 +01002818 bcm->current_core->initialized = 0;
John W. Linvillef2223132006-01-23 16:59:58 -05002819}
2820
2821/* http://bcm-specs.sipsolutions.net/80211Init */
2822static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2823{
Michael Buesche9357c02006-03-13 19:27:34 +01002824 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2825 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002826 u32 ucodeflags;
2827 int err;
2828 u32 sbimconfiglow;
2829 u8 limit;
2830
2831 if (bcm->chip_rev < 5) {
2832 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
2833 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
2834 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
2835 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
2836 sbimconfiglow |= 0x32;
2837 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
2838 sbimconfiglow |= 0x53;
2839 else
2840 assert(0);
2841 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
2842 }
2843
2844 bcm43xx_phy_calibrate(bcm);
2845 err = bcm43xx_chip_init(bcm);
2846 if (err)
2847 goto out;
2848
2849 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
2850 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
2851
2852 if (0 /*FIXME: which condition has to be used here? */)
2853 ucodeflags |= 0x00000010;
2854
2855 /* HW decryption needs to be set now */
2856 ucodeflags |= 0x40000000;
2857
Michael Buesche9357c02006-03-13 19:27:34 +01002858 if (phy->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -05002859 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
Michael Buesche9357c02006-03-13 19:27:34 +01002860 if (phy->rev == 1)
John W. Linvillef2223132006-01-23 16:59:58 -05002861 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
2862 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
2863 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
Michael Buesche9357c02006-03-13 19:27:34 +01002864 } else if (phy->type == BCM43xx_PHYTYPE_B) {
John W. Linvillef2223132006-01-23 16:59:58 -05002865 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
Michael Buesche9357c02006-03-13 19:27:34 +01002866 if (phy->rev >= 2 && radio->version == 0x2050)
John W. Linvillef2223132006-01-23 16:59:58 -05002867 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
2868 }
2869
2870 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2871 BCM43xx_UCODEFLAGS_OFFSET)) {
2872 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2873 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
2874 }
2875
2876 /* Short/Long Retry Limit.
2877 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
2878 * the chip-internal counter.
2879 */
2880 limit = limit_value(modparam_short_retry, 0, 0xF);
2881 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
2882 limit = limit_value(modparam_long_retry, 0, 0xF);
2883 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
2884
2885 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
2886 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
2887
2888 bcm43xx_rate_memory_init(bcm);
2889
2890 /* Minimum Contention Window */
Michael Buesche9357c02006-03-13 19:27:34 +01002891 if (phy->type == BCM43xx_PHYTYPE_B)
John W. Linvillef2223132006-01-23 16:59:58 -05002892 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
2893 else
2894 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
2895 /* Maximum Contention Window */
2896 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
2897
2898 bcm43xx_gen_bssid(bcm);
2899 bcm43xx_write_mac_bssid_templates(bcm);
2900
2901 if (bcm->current_core->rev >= 5)
2902 bcm43xx_write16(bcm, 0x043C, 0x000C);
2903
Michael Buesch77db31e2006-02-12 16:47:44 +01002904 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05002905 err = bcm43xx_pio_init(bcm);
Michael Buesch77db31e2006-02-12 16:47:44 +01002906 else
2907 err = bcm43xx_dma_init(bcm);
2908 if (err)
2909 goto err_chip_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002910 bcm43xx_write16(bcm, 0x0612, 0x0050);
2911 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2912 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2913
2914 bcm43xx_mac_enable(bcm);
2915 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2916
Michael Buesche9357c02006-03-13 19:27:34 +01002917 bcm->current_core->initialized = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002918out:
2919 return err;
2920
2921err_chip_cleanup:
2922 bcm43xx_chip_cleanup(bcm);
2923 goto out;
2924}
2925
2926static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
2927{
2928 int err;
2929 u16 pci_status;
2930
2931 err = bcm43xx_pctl_set_crystal(bcm, 1);
2932 if (err)
2933 goto out;
2934 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
2935 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
2936
2937out:
2938 return err;
2939}
2940
2941static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
2942{
2943 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
2944 bcm43xx_pctl_set_crystal(bcm, 0);
2945}
2946
Michael Buesch489423c2006-02-13 00:11:07 +01002947static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
2948 u32 address,
2949 u32 data)
John W. Linvillef2223132006-01-23 16:59:58 -05002950{
2951 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
2952 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
2953}
2954
2955static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
2956{
2957 int err;
2958 struct bcm43xx_coreinfo *old_core;
2959
2960 old_core = bcm->current_core;
2961 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2962 if (err)
2963 goto out;
2964
2965 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
2966
2967 bcm43xx_switch_core(bcm, old_core);
2968 assert(err == 0);
2969out:
2970 return err;
2971}
2972
2973/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
2974 * To enable core 0, pass a core_mask of 1<<0
2975 */
2976static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
2977 u32 core_mask)
2978{
2979 u32 backplane_flag_nr;
2980 u32 value;
2981 struct bcm43xx_coreinfo *old_core;
2982 int err = 0;
2983
2984 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
2985 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
2986
2987 old_core = bcm->current_core;
2988 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2989 if (err)
2990 goto out;
2991
2992 if (bcm->core_pci.rev < 6) {
2993 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
2994 value |= (1 << backplane_flag_nr);
2995 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
2996 } else {
2997 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
2998 if (err) {
2999 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3000 goto out_switch_back;
3001 }
3002 value |= core_mask << 8;
3003 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3004 if (err) {
3005 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3006 goto out_switch_back;
3007 }
3008 }
3009
3010 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3011 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3012 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3013
3014 if (bcm->core_pci.rev < 5) {
3015 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3016 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3017 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3018 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3019 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3020 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3021 err = bcm43xx_pcicore_commit_settings(bcm);
3022 assert(err == 0);
3023 }
3024
3025out_switch_back:
3026 err = bcm43xx_switch_core(bcm, old_core);
3027out:
3028 return err;
3029}
3030
3031static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3032{
3033 ieee80211softmac_start(bcm->net_dev);
3034}
3035
Michael Bueschab4977f2006-02-12 22:40:39 +01003036static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003037{
Michael Buesche9357c02006-03-13 19:27:34 +01003038 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003039
Michael Bueschab4977f2006-02-12 22:40:39 +01003040 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3041 return;
John W. Linvillef2223132006-01-23 16:59:58 -05003042
Michael Bueschab4977f2006-02-12 22:40:39 +01003043 bcm43xx_mac_suspend(bcm);
3044 bcm43xx_phy_lo_g_measure(bcm);
3045 bcm43xx_mac_enable(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003046}
3047
Michael Bueschab4977f2006-02-12 22:40:39 +01003048static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003049{
John W. Linvillef2223132006-01-23 16:59:58 -05003050 bcm43xx_phy_lo_mark_all_unused(bcm);
3051 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3052 bcm43xx_mac_suspend(bcm);
3053 bcm43xx_calc_nrssi_slope(bcm);
3054 bcm43xx_mac_enable(bcm);
3055 }
John W. Linvillef2223132006-01-23 16:59:58 -05003056}
3057
Michael Bueschab4977f2006-02-12 22:40:39 +01003058static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003059{
John W. Linvillef2223132006-01-23 16:59:58 -05003060 /* Update device statistics. */
3061 bcm43xx_calculate_link_quality(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003062}
John W. Linvillef2223132006-01-23 16:59:58 -05003063
Michael Bueschab4977f2006-02-12 22:40:39 +01003064static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3065{
Michael Buesche9357c02006-03-13 19:27:34 +01003066 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
3067 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003068
3069 if (phy->type == BCM43xx_PHYTYPE_G) {
3070 //TODO: update_aci_moving_average
3071 if (radio->aci_enable && radio->aci_wlan_automatic) {
3072 bcm43xx_mac_suspend(bcm);
3073 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3074 if (0 /*TODO: bunch of conditions*/) {
3075 bcm43xx_radio_set_interference_mitigation(bcm,
3076 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3077 }
3078 } else if (1/*TODO*/) {
3079 /*
3080 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3081 bcm43xx_radio_set_interference_mitigation(bcm,
3082 BCM43xx_RADIO_INTERFMODE_NONE);
3083 }
3084 */
3085 }
3086 bcm43xx_mac_enable(bcm);
3087 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3088 phy->rev == 1) {
3089 //TODO: implement rev1 workaround
3090 }
John W. Linvillef2223132006-01-23 16:59:58 -05003091 }
Michael Bueschab4977f2006-02-12 22:40:39 +01003092 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3093 //TODO for APHY (temperature?)
3094}
3095
3096static void bcm43xx_periodic_task_handler(unsigned long d)
3097{
3098 struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
3099 unsigned long flags;
3100 unsigned int state;
3101
Michael Bueschefccb642006-03-11 13:39:14 +01003102 bcm43xx_lock_mmio(bcm, flags);
Michael Bueschab4977f2006-02-12 22:40:39 +01003103
3104 assert(bcm->initialized);
3105 state = bcm->periodic_state;
3106 if (state % 8 == 0)
3107 bcm43xx_periodic_every120sec(bcm);
3108 if (state % 4 == 0)
3109 bcm43xx_periodic_every60sec(bcm);
3110 if (state % 2 == 0)
3111 bcm43xx_periodic_every30sec(bcm);
3112 bcm43xx_periodic_every15sec(bcm);
3113 bcm->periodic_state = state + 1;
3114
3115 mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
3116
Michael Bueschefccb642006-03-11 13:39:14 +01003117 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003118}
3119
John W. Linvillef2223132006-01-23 16:59:58 -05003120static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3121{
Michael Bueschab4977f2006-02-12 22:40:39 +01003122 del_timer_sync(&bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003123}
3124
John W. Linvillef2223132006-01-23 16:59:58 -05003125static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3126{
Michael Bueschab4977f2006-02-12 22:40:39 +01003127 struct timer_list *timer = &(bcm->periodic_tasks);
John W. Linvillef2223132006-01-23 16:59:58 -05003128
Michael Buesch1d1a73c2006-02-21 18:19:59 +01003129 assert(bcm->initialized);
Michael Bueschab4977f2006-02-12 22:40:39 +01003130 setup_timer(timer,
3131 bcm43xx_periodic_task_handler,
3132 (unsigned long)bcm);
3133 timer->expires = jiffies;
3134 add_timer(timer);
John W. Linvillef2223132006-01-23 16:59:58 -05003135}
3136
3137static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3138{
3139 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3140 0x0056) * 2;
3141 bcm43xx_clear_keys(bcm);
3142}
3143
3144/* This is the opposite of bcm43xx_init_board() */
3145static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3146{
3147 int i, err;
3148 unsigned long flags;
3149
Michael Buesch367f8992006-02-28 15:32:19 +01003150 bcm43xx_sysfs_unregister(bcm);
3151
Michael Bueschab4977f2006-02-12 22:40:39 +01003152 bcm43xx_periodic_tasks_delete(bcm);
3153
Michael Bueschefccb642006-03-11 13:39:14 +01003154 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003155 bcm->initialized = 0;
3156 bcm->shutting_down = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003157 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003158
John W. Linvillef2223132006-01-23 16:59:58 -05003159 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003160 if (!bcm->core_80211[i].available)
John W. Linvillef2223132006-01-23 16:59:58 -05003161 continue;
Michael Buesche9357c02006-03-13 19:27:34 +01003162 if (!bcm->core_80211[i].initialized)
John W. Linvillef2223132006-01-23 16:59:58 -05003163 continue;
3164
3165 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3166 assert(err == 0);
3167 bcm43xx_wireless_core_cleanup(bcm);
3168 }
3169
3170 bcm43xx_pctl_set_crystal(bcm, 0);
3171
Michael Bueschefccb642006-03-11 13:39:14 +01003172 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003173 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003174 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003175}
3176
3177static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3178{
3179 int i, err;
John W. Linvillef2223132006-01-23 16:59:58 -05003180 int connect_phy;
3181 unsigned long flags;
3182
3183 might_sleep();
3184
Michael Bueschefccb642006-03-11 13:39:14 +01003185 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003186 bcm->initialized = 0;
3187 bcm->shutting_down = 0;
Michael Bueschefccb642006-03-11 13:39:14 +01003188 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003189
3190 err = bcm43xx_pctl_set_crystal(bcm, 1);
3191 if (err)
3192 goto out;
3193 err = bcm43xx_pctl_init(bcm);
3194 if (err)
3195 goto err_crystal_off;
3196 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3197 if (err)
3198 goto err_crystal_off;
3199
3200 tasklet_enable(&bcm->isr_tasklet);
Michael Buesche9357c02006-03-13 19:27:34 +01003201 for (i = 0; i < bcm->nr_80211_available; i++) {
John W. Linvillef2223132006-01-23 16:59:58 -05003202 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3203 assert(err != -ENODEV);
3204 if (err)
3205 goto err_80211_unwind;
3206
3207 /* Enable the selected wireless core.
3208 * Connect PHY only on the first core.
3209 */
3210 if (!bcm43xx_core_enabled(bcm)) {
Michael Buesche9357c02006-03-13 19:27:34 +01003211 if (bcm->nr_80211_available == 1) {
3212 connect_phy = bcm43xx_current_phy(bcm)->connected;
John W. Linvillef2223132006-01-23 16:59:58 -05003213 } else {
3214 if (i == 0)
3215 connect_phy = 1;
3216 else
3217 connect_phy = 0;
3218 }
3219 bcm43xx_wireless_core_reset(bcm, connect_phy);
3220 }
3221
3222 if (i != 0)
3223 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3224
3225 err = bcm43xx_wireless_core_init(bcm);
3226 if (err)
3227 goto err_80211_unwind;
3228
3229 if (i != 0) {
3230 bcm43xx_mac_suspend(bcm);
3231 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3232 bcm43xx_radio_turn_off(bcm);
3233 }
3234 }
3235 bcm->active_80211_core = &bcm->core_80211[0];
Michael Buesche9357c02006-03-13 19:27:34 +01003236 if (bcm->nr_80211_available >= 2) {
John W. Linvillef2223132006-01-23 16:59:58 -05003237 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3238 bcm43xx_mac_enable(bcm);
3239 }
3240 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3241 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3242 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3243 bcm43xx_security_init(bcm);
3244 bcm43xx_softmac_init(bcm);
3245
3246 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3247
Michael Buesche9357c02006-03-13 19:27:34 +01003248 if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
John W. Linvillef2223132006-01-23 16:59:58 -05003249 bcm43xx_mac_suspend(bcm);
Michael Buesche9357c02006-03-13 19:27:34 +01003250 bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05003251 bcm43xx_mac_enable(bcm);
3252 }
Michael Bueschcad2b312006-02-21 18:08:55 +01003253
3254 /* Initialization of the board is done. Flag it as such. */
Michael Bueschefccb642006-03-11 13:39:14 +01003255 bcm43xx_lock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003256 bcm->initialized = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003257 bcm43xx_unlock(bcm, flags);
Michael Bueschcad2b312006-02-21 18:08:55 +01003258
John W. Linvillef2223132006-01-23 16:59:58 -05003259 bcm43xx_periodic_tasks_setup(bcm);
Michael Buesch367f8992006-02-28 15:32:19 +01003260 bcm43xx_sysfs_register(bcm);
3261 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
John W. Linvillef2223132006-01-23 16:59:58 -05003262
3263 assert(err == 0);
3264out:
3265 return err;
3266
3267err_80211_unwind:
3268 tasklet_disable(&bcm->isr_tasklet);
3269 /* unwind all 80211 initialization */
Michael Buesche9357c02006-03-13 19:27:34 +01003270 for (i = 0; i < bcm->nr_80211_available; i++) {
3271 if (!bcm->core_80211[i].initialized)
John W. Linvillef2223132006-01-23 16:59:58 -05003272 continue;
3273 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3274 bcm43xx_wireless_core_cleanup(bcm);
3275 }
3276err_crystal_off:
3277 bcm43xx_pctl_set_crystal(bcm, 0);
3278 goto out;
3279}
3280
3281static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3282{
3283 struct pci_dev *pci_dev = bcm->pci_dev;
3284 int i;
3285
3286 bcm43xx_chipset_detach(bcm);
3287 /* Do _not_ access the chip, after it is detached. */
3288 iounmap(bcm->mmio_addr);
3289
3290 pci_release_regions(pci_dev);
3291 pci_disable_device(pci_dev);
3292
3293 /* Free allocated structures/fields */
3294 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003295 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3296 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3297 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
John W. Linvillef2223132006-01-23 16:59:58 -05003298 }
3299}
3300
3301static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3302{
Michael Buesche9357c02006-03-13 19:27:34 +01003303 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003304 u16 value;
3305 u8 phy_version;
3306 u8 phy_type;
3307 u8 phy_rev;
3308 int phy_rev_ok = 1;
3309 void *p;
3310
3311 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3312
3313 phy_version = (value & 0xF000) >> 12;
3314 phy_type = (value & 0x0F00) >> 8;
3315 phy_rev = (value & 0x000F);
3316
3317 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3318 phy_version, phy_type, phy_rev);
3319
3320 switch (phy_type) {
3321 case BCM43xx_PHYTYPE_A:
3322 if (phy_rev >= 4)
3323 phy_rev_ok = 0;
3324 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3325 * if we switch 80211 cores after init is done.
3326 * As we do not implement on the fly switching between
3327 * wireless cores, I will leave this as a future task.
3328 */
3329 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3330 bcm->ieee->mode = IEEE_A;
3331 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3332 IEEE80211_24GHZ_BAND;
3333 break;
3334 case BCM43xx_PHYTYPE_B:
3335 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3336 phy_rev_ok = 0;
3337 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3338 bcm->ieee->mode = IEEE_B;
3339 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3340 break;
3341 case BCM43xx_PHYTYPE_G:
3342 if (phy_rev > 7)
3343 phy_rev_ok = 0;
3344 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3345 IEEE80211_CCK_MODULATION;
3346 bcm->ieee->mode = IEEE_G;
3347 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3348 break;
3349 default:
3350 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3351 phy_type);
3352 return -ENODEV;
3353 };
3354 if (!phy_rev_ok) {
3355 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3356 phy_rev);
3357 }
3358
Michael Buesch489423c2006-02-13 00:11:07 +01003359 phy->version = phy_version;
3360 phy->type = phy_type;
3361 phy->rev = phy_rev;
John W. Linvillef2223132006-01-23 16:59:58 -05003362 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3363 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3364 GFP_KERNEL);
3365 if (!p)
3366 return -ENOMEM;
Michael Buesch489423c2006-02-13 00:11:07 +01003367 phy->_lo_pairs = p;
John W. Linvillef2223132006-01-23 16:59:58 -05003368 }
3369
3370 return 0;
3371}
3372
3373static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3374{
3375 struct pci_dev *pci_dev = bcm->pci_dev;
3376 struct net_device *net_dev = bcm->net_dev;
3377 int err;
3378 int i;
Michael Buesch4a1821e2006-03-18 20:19:12 +01003379 unsigned long mmio_start, mmio_flags, mmio_len;
John W. Linvillef2223132006-01-23 16:59:58 -05003380 u32 coremask;
3381
3382 err = pci_enable_device(pci_dev);
3383 if (err) {
3384 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
John W. Linvillef2223132006-01-23 16:59:58 -05003385 goto out;
3386 }
John W. Linvillef2223132006-01-23 16:59:58 -05003387 mmio_start = pci_resource_start(pci_dev, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05003388 mmio_flags = pci_resource_flags(pci_dev, 0);
3389 mmio_len = pci_resource_len(pci_dev, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05003390 if (!(mmio_flags & IORESOURCE_MEM)) {
3391 printk(KERN_ERR PFX
3392 "%s, region #0 not an MMIO resource, aborting\n",
3393 pci_name(pci_dev));
3394 err = -ENODEV;
3395 goto err_pci_disable;
3396 }
Michael Buesch65f3f192006-01-31 20:11:38 +01003397 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
John W. Linvillef2223132006-01-23 16:59:58 -05003398 if (err) {
3399 printk(KERN_ERR PFX
3400 "could not access PCI resources (%i)\n", err);
3401 goto err_pci_disable;
3402 }
John W. Linvillef2223132006-01-23 16:59:58 -05003403 /* enable PCI bus-mastering */
3404 pci_set_master(pci_dev);
Michael Buesch4a1821e2006-03-18 20:19:12 +01003405 bcm->mmio_addr = ioremap(mmio_start, mmio_len);
3406 if (!bcm->mmio_addr) {
John W. Linvillef2223132006-01-23 16:59:58 -05003407 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3408 pci_name(pci_dev));
3409 err = -EIO;
3410 goto err_pci_release;
3411 }
John W. Linvillef2223132006-01-23 16:59:58 -05003412 bcm->mmio_len = mmio_len;
Michael Buesch4a1821e2006-03-18 20:19:12 +01003413 net_dev->base_addr = (unsigned long)bcm->mmio_addr;
John W. Linvillef2223132006-01-23 16:59:58 -05003414
3415 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3416 &bcm->board_vendor);
3417 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3418 &bcm->board_type);
3419 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3420 &bcm->board_revision);
3421
3422 err = bcm43xx_chipset_attach(bcm);
3423 if (err)
3424 goto err_iounmap;
3425 err = bcm43xx_pctl_init(bcm);
3426 if (err)
3427 goto err_chipset_detach;
3428 err = bcm43xx_probe_cores(bcm);
3429 if (err)
3430 goto err_chipset_detach;
3431
John W. Linvillef2223132006-01-23 16:59:58 -05003432 /* Attach all IO cores to the backplane. */
3433 coremask = 0;
Michael Buesche9357c02006-03-13 19:27:34 +01003434 for (i = 0; i < bcm->nr_80211_available; i++)
John W. Linvillef2223132006-01-23 16:59:58 -05003435 coremask |= (1 << bcm->core_80211[i].index);
3436 //FIXME: Also attach some non80211 cores?
3437 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3438 if (err) {
3439 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3440 goto err_chipset_detach;
3441 }
3442
Michael Bueschea0922b2006-02-19 14:09:20 +01003443 err = bcm43xx_sprom_extract(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003444 if (err)
3445 goto err_chipset_detach;
3446 err = bcm43xx_leds_init(bcm);
3447 if (err)
3448 goto err_chipset_detach;
3449
Michael Buesche9357c02006-03-13 19:27:34 +01003450 for (i = 0; i < bcm->nr_80211_available; i++) {
John W. Linvillef2223132006-01-23 16:59:58 -05003451 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3452 assert(err != -ENODEV);
3453 if (err)
3454 goto err_80211_unwind;
3455
3456 /* Enable the selected wireless core.
3457 * Connect PHY only on the first core.
3458 */
3459 bcm43xx_wireless_core_reset(bcm, (i == 0));
3460
3461 err = bcm43xx_read_phyinfo(bcm);
3462 if (err && (i == 0))
3463 goto err_80211_unwind;
3464
3465 err = bcm43xx_read_radioinfo(bcm);
3466 if (err && (i == 0))
3467 goto err_80211_unwind;
3468
3469 err = bcm43xx_validate_chip(bcm);
3470 if (err && (i == 0))
3471 goto err_80211_unwind;
3472
3473 bcm43xx_radio_turn_off(bcm);
3474 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3475 if (err)
3476 goto err_80211_unwind;
3477 bcm43xx_wireless_core_disable(bcm);
3478 }
3479 bcm43xx_pctl_set_crystal(bcm, 0);
3480
3481 /* Set the MAC address in the networking subsystem */
Michael Buesche9357c02006-03-13 19:27:34 +01003482 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
John W. Linvillef2223132006-01-23 16:59:58 -05003483 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3484 else
3485 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3486
3487 bcm43xx_geo_init(bcm);
3488
3489 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3490 "Broadcom %04X", bcm->chip_id);
3491
3492 assert(err == 0);
3493out:
3494 return err;
3495
3496err_80211_unwind:
3497 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003498 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3499 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3500 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
John W. Linvillef2223132006-01-23 16:59:58 -05003501 }
3502err_chipset_detach:
3503 bcm43xx_chipset_detach(bcm);
3504err_iounmap:
3505 iounmap(bcm->mmio_addr);
3506err_pci_release:
3507 pci_release_regions(pci_dev);
3508err_pci_disable:
3509 pci_disable_device(pci_dev);
3510 goto out;
3511}
3512
John W. Linvillef2223132006-01-23 16:59:58 -05003513/* Do the Hardware IO operations to send the txb */
3514static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3515 struct ieee80211_txb *txb)
3516{
3517 int err = -ENODEV;
3518
Michael Buesch77db31e2006-02-12 16:47:44 +01003519 if (bcm43xx_using_pio(bcm))
3520 err = bcm43xx_pio_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003521 else
Michael Bueschea72ab22006-01-27 17:26:20 +01003522 err = bcm43xx_dma_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003523
3524 return err;
3525}
3526
3527static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3528 u8 channel)
3529{
3530 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3531 unsigned long flags;
3532
Michael Bueschefccb642006-03-11 13:39:14 +01003533 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003534 bcm43xx_mac_suspend(bcm);
3535 bcm43xx_radio_selectchannel(bcm, channel, 0);
3536 bcm43xx_mac_enable(bcm);
Michael Bueschefccb642006-03-11 13:39:14 +01003537 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003538}
3539
3540/* set_security() callback in struct ieee80211_device */
3541static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
3542 struct ieee80211_security *sec)
3543{
3544 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3545 struct ieee80211_security *secinfo = &bcm->ieee->sec;
3546 unsigned long flags;
3547 int keyidx;
3548
3549 dprintk(KERN_INFO PFX "set security called\n");
Michael Bueschefccb642006-03-11 13:39:14 +01003550
3551 bcm43xx_lock_mmio(bcm, flags);
3552
John W. Linvillef2223132006-01-23 16:59:58 -05003553 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
3554 if (sec->flags & (1<<keyidx)) {
3555 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
3556 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
3557 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
3558 }
3559
3560 if (sec->flags & SEC_ACTIVE_KEY) {
3561 secinfo->active_key = sec->active_key;
3562 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
3563 }
3564 if (sec->flags & SEC_UNICAST_GROUP) {
3565 secinfo->unicast_uses_group = sec->unicast_uses_group;
3566 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
3567 }
3568 if (sec->flags & SEC_LEVEL) {
3569 secinfo->level = sec->level;
3570 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
3571 }
3572 if (sec->flags & SEC_ENABLED) {
3573 secinfo->enabled = sec->enabled;
3574 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
3575 }
3576 if (sec->flags & SEC_ENCRYPT) {
3577 secinfo->encrypt = sec->encrypt;
3578 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
3579 }
3580 if (bcm->initialized && !bcm->ieee->host_encrypt) {
3581 if (secinfo->enabled) {
3582 /* upload WEP keys to hardware */
3583 char null_address[6] = { 0 };
3584 u8 algorithm = 0;
3585 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
3586 if (!(sec->flags & (1<<keyidx)))
3587 continue;
3588 switch (sec->encode_alg[keyidx]) {
3589 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
3590 case SEC_ALG_WEP:
3591 algorithm = BCM43xx_SEC_ALGO_WEP;
3592 if (secinfo->key_sizes[keyidx] == 13)
3593 algorithm = BCM43xx_SEC_ALGO_WEP104;
3594 break;
3595 case SEC_ALG_TKIP:
3596 FIXME();
3597 algorithm = BCM43xx_SEC_ALGO_TKIP;
3598 break;
3599 case SEC_ALG_CCMP:
3600 FIXME();
3601 algorithm = BCM43xx_SEC_ALGO_AES;
3602 break;
3603 default:
3604 assert(0);
3605 break;
3606 }
3607 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
3608 bcm->key[keyidx].enabled = 1;
3609 bcm->key[keyidx].algorithm = algorithm;
3610 }
3611 } else
3612 bcm43xx_clear_keys(bcm);
3613 }
Michael Bueschefccb642006-03-11 13:39:14 +01003614 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003615}
3616
3617/* hard_start_xmit() callback in struct ieee80211_device */
3618static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
3619 struct net_device *net_dev,
3620 int pri)
3621{
3622 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3623 int err = -ENODEV;
3624 unsigned long flags;
3625
Michael Bueschefccb642006-03-11 13:39:14 +01003626 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003627 if (likely(bcm->initialized))
3628 err = bcm43xx_tx(bcm, txb);
Michael Bueschefccb642006-03-11 13:39:14 +01003629 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003630
3631 return err;
3632}
3633
3634static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
3635{
3636 return &(bcm43xx_priv(net_dev)->ieee->stats);
3637}
3638
3639static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
3640{
3641 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschefccb642006-03-11 13:39:14 +01003642 unsigned long flags;
John W. Linvillef2223132006-01-23 16:59:58 -05003643
Michael Bueschefccb642006-03-11 13:39:14 +01003644 bcm43xx_lock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003645 bcm43xx_controller_restart(bcm, "TX timeout");
Michael Bueschefccb642006-03-11 13:39:14 +01003646 bcm43xx_unlock_mmio(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003647}
3648
3649#ifdef CONFIG_NET_POLL_CONTROLLER
3650static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3651{
3652 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3653 unsigned long flags;
3654
3655 local_irq_save(flags);
3656 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3657 local_irq_restore(flags);
3658}
3659#endif /* CONFIG_NET_POLL_CONTROLLER */
3660
3661static int bcm43xx_net_open(struct net_device *net_dev)
3662{
3663 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3664
3665 return bcm43xx_init_board(bcm);
3666}
3667
3668static int bcm43xx_net_stop(struct net_device *net_dev)
3669{
3670 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3671
3672 ieee80211softmac_stop(net_dev);
3673 bcm43xx_disable_interrupts_sync(bcm, NULL);
3674 bcm43xx_free_board(bcm);
3675
3676 return 0;
3677}
3678
Michael Buesch77db31e2006-02-12 16:47:44 +01003679static int bcm43xx_init_private(struct bcm43xx_private *bcm,
3680 struct net_device *net_dev,
Michael Bueschab4977f2006-02-12 22:40:39 +01003681 struct pci_dev *pci_dev)
John W. Linvillef2223132006-01-23 16:59:58 -05003682{
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003683 int err;
3684
John W. Linvillef2223132006-01-23 16:59:58 -05003685 bcm->ieee = netdev_priv(net_dev);
3686 bcm->softmac = ieee80211_priv(net_dev);
3687 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
John W. Linvillef2223132006-01-23 16:59:58 -05003688
John W. Linvillef2223132006-01-23 16:59:58 -05003689 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3690 bcm->pci_dev = pci_dev;
3691 bcm->net_dev = net_dev;
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003692 bcm->bad_frames_preempt = modparam_bad_frames_preempt;
Michael Bueschefccb642006-03-11 13:39:14 +01003693 spin_lock_init(&bcm->_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05003694 tasklet_init(&bcm->isr_tasklet,
3695 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
3696 (unsigned long)bcm);
3697 tasklet_disable_nosync(&bcm->isr_tasklet);
3698 if (modparam_pio) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003699 bcm->__using_pio = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05003700 } else {
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003701 err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
3702 err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
3703 if (err) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003704#ifdef CONFIG_BCM43XX_PIO
John W. Linvillef2223132006-01-23 16:59:58 -05003705 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
Michael Buesch77db31e2006-02-12 16:47:44 +01003706 bcm->__using_pio = 1;
3707#else
3708 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
3709 "Recompile the driver with PIO support, please.\n");
3710 return -ENODEV;
3711#endif /* CONFIG_BCM43XX_PIO */
John W. Linvillef2223132006-01-23 16:59:58 -05003712 }
3713 }
3714 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
3715
3716 /* default to sw encryption for now */
3717 bcm->ieee->host_build_iv = 0;
3718 bcm->ieee->host_encrypt = 1;
3719 bcm->ieee->host_decrypt = 1;
3720
3721 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
3722 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
3723 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
3724 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
Michael Buesch77db31e2006-02-12 16:47:44 +01003725
3726 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05003727}
3728
3729static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
3730 const struct pci_device_id *ent)
3731{
3732 struct net_device *net_dev;
3733 struct bcm43xx_private *bcm;
John W. Linvillef2223132006-01-23 16:59:58 -05003734 int err;
3735
3736#ifdef CONFIG_BCM947XX
3737 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
3738 return -ENODEV;
3739#endif
3740
3741#ifdef DEBUG_SINGLE_DEVICE_ONLY
3742 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
3743 return -ENODEV;
3744#endif
3745
3746 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
3747 if (!net_dev) {
3748 printk(KERN_ERR PFX
3749 "could not allocate ieee80211 device %s\n",
3750 pci_name(pdev));
3751 err = -ENOMEM;
3752 goto out;
3753 }
3754 /* initialize the net_device struct */
3755 SET_MODULE_OWNER(net_dev);
3756 SET_NETDEV_DEV(net_dev, &pdev->dev);
3757
3758 net_dev->open = bcm43xx_net_open;
3759 net_dev->stop = bcm43xx_net_stop;
3760 net_dev->get_stats = bcm43xx_net_get_stats;
3761 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
3762#ifdef CONFIG_NET_POLL_CONTROLLER
3763 net_dev->poll_controller = bcm43xx_net_poll_controller;
3764#endif
3765 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
3766 net_dev->irq = pdev->irq;
Michael Buesch6465ce12006-02-02 19:11:08 +01003767 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
John W. Linvillef2223132006-01-23 16:59:58 -05003768
3769 /* initialize the bcm43xx_private struct */
3770 bcm = bcm43xx_priv(net_dev);
3771 memset(bcm, 0, sizeof(*bcm));
Michael Bueschab4977f2006-02-12 22:40:39 +01003772 err = bcm43xx_init_private(bcm, net_dev, pdev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003773 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003774 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003775
3776 pci_set_drvdata(pdev, net_dev);
3777
3778 err = bcm43xx_attach_board(bcm);
3779 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003780 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003781
3782 err = register_netdev(net_dev);
3783 if (err) {
3784 printk(KERN_ERR PFX "Cannot register net device, "
3785 "aborting.\n");
3786 err = -ENOMEM;
3787 goto err_detach_board;
3788 }
3789
3790 bcm43xx_debugfs_add_device(bcm);
3791
3792 assert(err == 0);
3793out:
3794 return err;
3795
3796err_detach_board:
3797 bcm43xx_detach_board(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003798err_free_netdev:
3799 free_ieee80211softmac(net_dev);
3800 goto out;
3801}
3802
3803static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3804{
3805 struct net_device *net_dev = pci_get_drvdata(pdev);
3806 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3807
3808 bcm43xx_debugfs_remove_device(bcm);
3809 unregister_netdev(net_dev);
3810 bcm43xx_detach_board(bcm);
3811 assert(bcm->ucode == NULL);
John W. Linvillef2223132006-01-23 16:59:58 -05003812 free_ieee80211softmac(net_dev);
3813}
3814
3815/* Hard-reset the chip. Do not call this directly.
3816 * Use bcm43xx_controller_restart()
3817 */
3818static void bcm43xx_chip_reset(void *_bcm)
3819{
3820 struct bcm43xx_private *bcm = _bcm;
3821 struct net_device *net_dev = bcm->net_dev;
3822 struct pci_dev *pci_dev = bcm->pci_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05003823 int err;
3824 int was_initialized = bcm->initialized;
3825
3826 netif_stop_queue(bcm->net_dev);
3827 tasklet_disable(&bcm->isr_tasklet);
3828
3829 bcm->firmware_norelease = 1;
3830 if (was_initialized)
3831 bcm43xx_free_board(bcm);
3832 bcm->firmware_norelease = 0;
3833 bcm43xx_detach_board(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003834 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003835 if (err)
3836 goto failure;
John W. Linvillef2223132006-01-23 16:59:58 -05003837 err = bcm43xx_attach_board(bcm);
3838 if (err)
3839 goto failure;
3840 if (was_initialized) {
3841 err = bcm43xx_init_board(bcm);
3842 if (err)
3843 goto failure;
3844 }
3845 netif_wake_queue(bcm->net_dev);
3846 printk(KERN_INFO PFX "Controller restarted\n");
3847
3848 return;
3849failure:
3850 printk(KERN_ERR PFX "Controller restart failed\n");
3851}
3852
3853/* Hard-reset the chip.
3854 * This can be called from interrupt or process context.
3855 * Make sure to _not_ re-enable device interrupts after this has been called.
3856*/
3857void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
3858{
3859 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
Michael Buesch73733842006-03-12 19:44:29 +01003860 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
John W. Linvillef2223132006-01-23 16:59:58 -05003861 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
3862 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003863 schedule_work(&bcm->restart_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003864}
3865
3866#ifdef CONFIG_PM
3867
3868static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
3869{
3870 struct net_device *net_dev = pci_get_drvdata(pdev);
3871 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3872 unsigned long flags;
3873 int try_to_shutdown = 0, err;
3874
3875 dprintk(KERN_INFO PFX "Suspending...\n");
3876
Michael Bueschefccb642006-03-11 13:39:14 +01003877 bcm43xx_lock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003878 bcm->was_initialized = bcm->initialized;
3879 if (bcm->initialized)
3880 try_to_shutdown = 1;
Michael Bueschefccb642006-03-11 13:39:14 +01003881 bcm43xx_unlock(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003882
3883 netif_device_detach(net_dev);
3884 if (try_to_shutdown) {
3885 ieee80211softmac_stop(net_dev);
3886 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
3887 if (unlikely(err)) {
3888 dprintk(KERN_ERR PFX "Suspend failed.\n");
3889 return -EAGAIN;
3890 }
3891 bcm->firmware_norelease = 1;
3892 bcm43xx_free_board(bcm);
3893 bcm->firmware_norelease = 0;
3894 }
3895 bcm43xx_chipset_detach(bcm);
3896
3897 pci_save_state(pdev);
3898 pci_disable_device(pdev);
3899 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3900
3901 dprintk(KERN_INFO PFX "Device suspended.\n");
3902
3903 return 0;
3904}
3905
3906static int bcm43xx_resume(struct pci_dev *pdev)
3907{
3908 struct net_device *net_dev = pci_get_drvdata(pdev);
3909 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3910 int err = 0;
3911
3912 dprintk(KERN_INFO PFX "Resuming...\n");
3913
3914 pci_set_power_state(pdev, 0);
3915 pci_enable_device(pdev);
3916 pci_restore_state(pdev);
3917
3918 bcm43xx_chipset_attach(bcm);
3919 if (bcm->was_initialized) {
3920 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3921 err = bcm43xx_init_board(bcm);
3922 }
3923 if (err) {
3924 printk(KERN_ERR PFX "Resume failed!\n");
3925 return err;
3926 }
3927
3928 netif_device_attach(net_dev);
3929
3930 /*FIXME: This should be handled by softmac instead. */
3931 schedule_work(&bcm->softmac->associnfo.work);
3932
3933 dprintk(KERN_INFO PFX "Device resumed.\n");
3934
3935 return 0;
3936}
3937
3938#endif /* CONFIG_PM */
3939
3940static struct pci_driver bcm43xx_pci_driver = {
Michael Buesch65f3f192006-01-31 20:11:38 +01003941 .name = KBUILD_MODNAME,
John W. Linvillef2223132006-01-23 16:59:58 -05003942 .id_table = bcm43xx_pci_tbl,
3943 .probe = bcm43xx_init_one,
3944 .remove = __devexit_p(bcm43xx_remove_one),
3945#ifdef CONFIG_PM
3946 .suspend = bcm43xx_suspend,
3947 .resume = bcm43xx_resume,
3948#endif /* CONFIG_PM */
3949};
3950
3951static int __init bcm43xx_init(void)
3952{
Michael Buesch65f3f192006-01-31 20:11:38 +01003953 printk(KERN_INFO KBUILD_MODNAME " driver\n");
John W. Linvillef2223132006-01-23 16:59:58 -05003954 bcm43xx_debugfs_init();
3955 return pci_register_driver(&bcm43xx_pci_driver);
3956}
3957
3958static void __exit bcm43xx_exit(void)
3959{
3960 pci_unregister_driver(&bcm43xx_pci_driver);
3961 bcm43xx_debugfs_exit();
3962}
3963
3964module_init(bcm43xx_init)
3965module_exit(bcm43xx_exit)