blob: 835a2df1fe30469f5affb05dfdd8cbc1651593cc [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"
Michael Bueschb35d6492006-04-13 02:32:58 +020055#include "bcm43xx_sysfs.h"
John W. Linvillef2223132006-01-23 16:59:58 -050056
57
58MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
59MODULE_AUTHOR("Martin Langer");
60MODULE_AUTHOR("Stefano Brivio");
61MODULE_AUTHOR("Michael Buesch");
62MODULE_LICENSE("GPL");
63
64#ifdef CONFIG_BCM947XX
65extern char *nvram_get(char *name);
66#endif
67
Michael Buesch77db31e2006-02-12 16:47:44 +010068#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
John W. Linvillef2223132006-01-23 16:59:58 -050069static int modparam_pio;
70module_param_named(pio, modparam_pio, int, 0444);
71MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
Michael Buesch77db31e2006-02-12 16:47:44 +010072#elif defined(CONFIG_BCM43XX_DMA)
73# define modparam_pio 0
74#elif defined(CONFIG_BCM43XX_PIO)
75# define modparam_pio 1
76#endif
John W. Linvillef2223132006-01-23 16:59:58 -050077
78static int modparam_bad_frames_preempt;
79module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
80MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
81
82static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
83module_param_named(short_retry, modparam_short_retry, int, 0444);
84MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
85
86static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
87module_param_named(long_retry, modparam_long_retry, int, 0444);
88MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
89
90static int modparam_locale = -1;
91module_param_named(locale, modparam_locale, int, 0444);
92MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
93
John W. Linvillef2223132006-01-23 16:59:58 -050094static int modparam_noleds;
95module_param_named(noleds, modparam_noleds, int, 0444);
96MODULE_PARM_DESC(noleds, "Turn off all LED activity");
97
98#ifdef CONFIG_BCM43XX_DEBUG
99static char modparam_fwpostfix[64];
100module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
101MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
102#else
103# define modparam_fwpostfix ""
104#endif /* CONFIG_BCM43XX_DEBUG*/
105
106
107/* If you want to debug with just a single device, enable this,
108 * where the string is the pci device ID (as given by the kernel's
109 * pci_name function) of the device to be used.
110 */
111//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0"
112
113/* If you want to enable printing of each MMIO access, enable this. */
114//#define DEBUG_ENABLE_MMIO_PRINT
115
116/* If you want to enable printing of MMIO access within
117 * ucode/pcm upload, initvals write, enable this.
118 */
119//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
120
121/* If you want to enable printing of PCI Config Space access, enable this */
122//#define DEBUG_ENABLE_PCILOG
123
124
Michael Buesch489423c2006-02-13 00:11:07 +0100125/* Detailed list maintained at:
126 * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
127 */
128 static struct pci_device_id bcm43xx_pci_tbl[] = {
129 /* Broadcom 4303 802.11b */
130 { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
Stefano Brivioec000ca92006-05-05 02:58:29 +0200131 /* Broadcom 4307 802.11b */
Michael Buesch489423c2006-02-13 00:11:07 +0100132 { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
Stefano Brivioec000ca92006-05-05 02:58:29 +0200133 /* Broadcom 4318 802.11b/g */
Michael Buesch489423c2006-02-13 00:11:07 +0100134 { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
Stefano Briviof03cc4f2006-05-05 03:02:25 +0200135 /* Broadcom 4319 802.11a/b/g */
136 { PCI_VENDOR_ID_BROADCOM, 0x4319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
Michael Buesch489423c2006-02-13 00:11:07 +0100137 /* Broadcom 4306 802.11b/g */
138 { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
Stefano Brivioec000ca92006-05-05 02:58:29 +0200139 /* Broadcom 4306 802.11a */
Michael Buesch489423c2006-02-13 00:11:07 +0100140// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
141 /* Broadcom 4309 802.11a/b/g */
142 { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
143 /* Broadcom 43XG 802.11b/g */
144 { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500145#ifdef CONFIG_BCM947XX
146 /* SB bus on BCM947xx */
147 { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
148#endif
Michael Buesch489423c2006-02-13 00:11:07 +0100149 { 0 },
John W. Linvillef2223132006-01-23 16:59:58 -0500150};
151MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
152
153static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
154{
155 u32 status;
156
157 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
158 if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
159 val = swab32(val);
160
161 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
Michael Buesch73733842006-03-12 19:44:29 +0100162 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500163 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
164}
165
166static inline
167void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
168 u16 routing, u16 offset)
169{
170 u32 control;
171
172 /* "offset" is the WORD offset. */
173
174 control = routing;
175 control <<= 16;
176 control |= offset;
177 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
178}
179
180u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
181 u16 routing, u16 offset)
182{
183 u32 ret;
184
185 if (routing == BCM43xx_SHM_SHARED) {
186 if (offset & 0x0003) {
187 /* Unaligned access */
188 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
189 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
190 ret <<= 16;
191 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
192 ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
193
194 return ret;
195 }
196 offset >>= 2;
197 }
198 bcm43xx_shm_control_word(bcm, routing, offset);
199 ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
200
201 return ret;
202}
203
204u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
205 u16 routing, u16 offset)
206{
207 u16 ret;
208
209 if (routing == BCM43xx_SHM_SHARED) {
210 if (offset & 0x0003) {
211 /* Unaligned access */
212 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
213 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
214
215 return ret;
216 }
217 offset >>= 2;
218 }
219 bcm43xx_shm_control_word(bcm, routing, offset);
220 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
221
222 return ret;
223}
224
225void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
226 u16 routing, u16 offset,
227 u32 value)
228{
229 if (routing == BCM43xx_SHM_SHARED) {
230 if (offset & 0x0003) {
231 /* Unaligned access */
232 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
Michael Buesch73733842006-03-12 19:44:29 +0100233 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500234 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
235 (value >> 16) & 0xffff);
Michael Buesch73733842006-03-12 19:44:29 +0100236 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500237 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
Michael Buesch73733842006-03-12 19:44:29 +0100238 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500239 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA,
240 value & 0xffff);
241 return;
242 }
243 offset >>= 2;
244 }
245 bcm43xx_shm_control_word(bcm, routing, offset);
Michael Buesch73733842006-03-12 19:44:29 +0100246 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500247 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
248}
249
250void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
251 u16 routing, u16 offset,
252 u16 value)
253{
254 if (routing == BCM43xx_SHM_SHARED) {
255 if (offset & 0x0003) {
256 /* Unaligned access */
257 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
Michael Buesch73733842006-03-12 19:44:29 +0100258 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500259 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
260 value);
261 return;
262 }
263 offset >>= 2;
264 }
265 bcm43xx_shm_control_word(bcm, routing, offset);
Michael Buesch73733842006-03-12 19:44:29 +0100266 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500267 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);
268}
269
270void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf)
271{
272 /* We need to be careful. As we read the TSF from multiple
273 * registers, we should take care of register overflows.
274 * In theory, the whole tsf read process should be atomic.
275 * We try to be atomic here, by restaring the read process,
276 * if any of the high registers changed (overflew).
277 */
278 if (bcm->current_core->rev >= 3) {
279 u32 low, high, high2;
280
281 do {
282 high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
283 low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW);
284 high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
285 } while (unlikely(high != high2));
286
287 *tsf = high;
288 *tsf <<= 32;
289 *tsf |= low;
290 } else {
291 u64 tmp;
292 u16 v0, v1, v2, v3;
293 u16 test1, test2, test3;
294
295 do {
296 v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
297 v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
298 v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
299 v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0);
300
301 test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
302 test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
303 test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
304 } while (v3 != test3 || v2 != test2 || v1 != test1);
305
306 *tsf = v3;
307 *tsf <<= 48;
308 tmp = v2;
309 tmp <<= 32;
310 *tsf |= tmp;
311 tmp = v1;
312 tmp <<= 16;
313 *tsf |= tmp;
314 *tsf |= v0;
315 }
316}
317
318void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
319{
320 u32 status;
321
322 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
323 status |= BCM43xx_SBF_TIME_UPDATE;
324 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
Michael Buesch73733842006-03-12 19:44:29 +0100325 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500326
327 /* Be careful with the in-progress timer.
328 * First zero out the low register, so we have a full
329 * register-overflow duration to complete the operation.
330 */
331 if (bcm->current_core->rev >= 3) {
332 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
333 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
334
John W. Linvillef2223132006-01-23 16:59:58 -0500335 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
Michael Buesch73733842006-03-12 19:44:29 +0100336 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500337 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
Michael Buesch73733842006-03-12 19:44:29 +0100338 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500339 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
340 } else {
341 u16 v0 = (tsf & 0x000000000000FFFFULL);
342 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
343 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
344 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
345
John W. Linvillef2223132006-01-23 16:59:58 -0500346 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
Michael Buesch73733842006-03-12 19:44:29 +0100347 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500348 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
Michael Buesch73733842006-03-12 19:44:29 +0100349 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500350 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
Michael Buesch73733842006-03-12 19:44:29 +0100351 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500352 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
Michael Buesch73733842006-03-12 19:44:29 +0100353 mmiowb();
John W. Linvillef2223132006-01-23 16:59:58 -0500354 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
355 }
356
357 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
358 status &= ~BCM43xx_SBF_TIME_UPDATE;
359 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
360}
361
John W. Linvillef2223132006-01-23 16:59:58 -0500362static
363void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
364 u16 offset,
365 const u8 *mac)
366{
367 u16 data;
368
369 offset |= 0x0020;
370 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
371
372 data = mac[0];
373 data |= mac[1] << 8;
374 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
375 data = mac[2];
376 data |= mac[3] << 8;
377 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
378 data = mac[4];
379 data |= mac[5] << 8;
380 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
381}
382
Michael Buesch489423c2006-02-13 00:11:07 +0100383static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
384 u16 offset)
John W. Linvillef2223132006-01-23 16:59:58 -0500385{
386 const u8 zero_addr[ETH_ALEN] = { 0 };
387
388 bcm43xx_macfilter_set(bcm, offset, zero_addr);
389}
390
391static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
392{
393 const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
394 const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
395 u8 mac_bssid[ETH_ALEN * 2];
396 int i;
397
398 memcpy(mac_bssid, mac, ETH_ALEN);
399 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
400
401 /* Write our MAC address and BSSID to template ram */
402 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
403 bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
404 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
405 bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
406 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
407 bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
408}
409
Michael Bueschb5e868e2006-03-25 16:27:32 +0100410//FIXME: Well, we should probably call them from somewhere.
411#if 0
Michael Buesch489423c2006-02-13 00:11:07 +0100412static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
John W. Linvillef2223132006-01-23 16:59:58 -0500413{
414 /* slot_time is in usec. */
Michael Buesche9357c02006-03-13 19:27:34 +0100415 if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G)
John W. Linvillef2223132006-01-23 16:59:58 -0500416 return;
417 bcm43xx_write16(bcm, 0x684, 510 + slot_time);
418 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
419}
420
Michael Buesch489423c2006-02-13 00:11:07 +0100421static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500422{
423 bcm43xx_set_slot_time(bcm, 9);
424}
425
Michael Buesch489423c2006-02-13 00:11:07 +0100426static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500427{
428 bcm43xx_set_slot_time(bcm, 20);
429}
Michael Bueschb5e868e2006-03-25 16:27:32 +0100430#endif
John W. Linvillef2223132006-01-23 16:59:58 -0500431
Michael Bueschb5e868e2006-03-25 16:27:32 +0100432/* FIXME: To get the MAC-filter working, we need to implement the
433 * following functions (and rename them :)
434 */
435#if 0
John W. Linvillef2223132006-01-23 16:59:58 -0500436static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
437{
438 bcm43xx_mac_suspend(bcm);
439 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
440
441 bcm43xx_ram_write(bcm, 0x0026, 0x0000);
442 bcm43xx_ram_write(bcm, 0x0028, 0x0000);
443 bcm43xx_ram_write(bcm, 0x007E, 0x0000);
444 bcm43xx_ram_write(bcm, 0x0080, 0x0000);
445 bcm43xx_ram_write(bcm, 0x047E, 0x0000);
446 bcm43xx_ram_write(bcm, 0x0480, 0x0000);
447
448 if (bcm->current_core->rev < 3) {
449 bcm43xx_write16(bcm, 0x0610, 0x8000);
450 bcm43xx_write16(bcm, 0x060E, 0x0000);
451 } else
452 bcm43xx_write32(bcm, 0x0188, 0x80000000);
453
454 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
455
Michael Buesche9357c02006-03-13 19:27:34 +0100456 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G &&
John W. Linvillef2223132006-01-23 16:59:58 -0500457 ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
458 bcm43xx_short_slot_timing_enable(bcm);
459
460 bcm43xx_mac_enable(bcm);
461}
462
John W. Linvillef2223132006-01-23 16:59:58 -0500463static void bcm43xx_associate(struct bcm43xx_private *bcm,
464 const u8 *mac)
465{
466 memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
467
468 bcm43xx_mac_suspend(bcm);
469 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
470 bcm43xx_write_mac_bssid_templates(bcm);
471 bcm43xx_mac_enable(bcm);
472}
Michael Bueschb5e868e2006-03-25 16:27:32 +0100473#endif
John W. Linvillef2223132006-01-23 16:59:58 -0500474
475/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
476 * Returns the _previously_ enabled IRQ mask.
477 */
478static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
479{
480 u32 old_mask;
481
482 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
483 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
484
485 return old_mask;
486}
487
488/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
489 * Returns the _previously_ enabled IRQ mask.
490 */
491static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
492{
493 u32 old_mask;
494
495 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
496 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
497
498 return old_mask;
499}
500
501/* Make sure we don't receive more data from the device. */
502static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
503{
504 u32 old;
505 unsigned long flags;
506
Michael Buesch78ff56a2006-06-05 20:24:10 +0200507 bcm43xx_lock_irqonly(bcm, flags);
508 if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
509 bcm43xx_unlock_irqonly(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500510 return -EBUSY;
511 }
512 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
513 tasklet_disable(&bcm->isr_tasklet);
Michael Buesch78ff56a2006-06-05 20:24:10 +0200514 bcm43xx_unlock_irqonly(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500515 if (oldstate)
516 *oldstate = old;
517
518 return 0;
519}
520
521static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
522{
Michael Buesche9357c02006-03-13 19:27:34 +0100523 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
524 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -0500525 u32 radio_id;
526 u16 manufact;
527 u16 version;
528 u8 revision;
529 s8 i;
530
531 if (bcm->chip_id == 0x4317) {
532 if (bcm->chip_rev == 0x00)
533 radio_id = 0x3205017F;
534 else if (bcm->chip_rev == 0x01)
535 radio_id = 0x4205017F;
536 else
537 radio_id = 0x5205017F;
538 } else {
539 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
540 radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
541 radio_id <<= 16;
542 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
543 radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
544 }
545
546 manufact = (radio_id & 0x00000FFF);
547 version = (radio_id & 0x0FFFF000) >> 12;
548 revision = (radio_id & 0xF0000000) >> 28;
549
Michael Buesch489423c2006-02-13 00:11:07 +0100550 dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
John W. Linvillef2223132006-01-23 16:59:58 -0500551 radio_id, manufact, version, revision);
552
Michael Buesch489423c2006-02-13 00:11:07 +0100553 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -0500554 case BCM43xx_PHYTYPE_A:
555 if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
556 goto err_unsupported_radio;
557 break;
558 case BCM43xx_PHYTYPE_B:
559 if ((version & 0xFFF0) != 0x2050)
560 goto err_unsupported_radio;
561 break;
562 case BCM43xx_PHYTYPE_G:
563 if (version != 0x2050)
564 goto err_unsupported_radio;
565 break;
566 }
567
Michael Buesch489423c2006-02-13 00:11:07 +0100568 radio->manufact = manufact;
569 radio->version = version;
570 radio->revision = revision;
John W. Linvillef2223132006-01-23 16:59:58 -0500571
572 /* Set default attenuation values. */
Michael Buesch6ecb2692006-03-20 00:01:04 +0100573 radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
574 radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
575 radio->txctl1 = bcm43xx_default_txctl1(bcm);
Michael Bueschadc40e92006-03-25 20:36:57 +0100576 radio->txctl2 = 0xFFFF;
Michael Buesche9357c02006-03-13 19:27:34 +0100577 if (phy->type == BCM43xx_PHYTYPE_A)
Michael Buesch489423c2006-02-13 00:11:07 +0100578 radio->txpower_desired = bcm->sprom.maxpower_aphy;
Michael Buesch393344f2006-02-05 15:28:20 +0100579 else
Michael Buesche9357c02006-03-13 19:27:34 +0100580 radio->txpower_desired = bcm->sprom.maxpower_bgphy;
John W. Linvillef2223132006-01-23 16:59:58 -0500581
582 /* Initialize the in-memory nrssi Lookup Table. */
583 for (i = 0; i < 64; i++)
Michael Buesch489423c2006-02-13 00:11:07 +0100584 radio->nrssi_lt[i] = i;
John W. Linvillef2223132006-01-23 16:59:58 -0500585
586 return 0;
587
588err_unsupported_radio:
589 printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
590 return -ENODEV;
591}
592
593static const char * bcm43xx_locale_iso(u8 locale)
594{
595 /* ISO 3166-1 country codes.
596 * Note that there aren't ISO 3166-1 codes for
597 * all or locales. (Not all locales are countries)
598 */
599 switch (locale) {
600 case BCM43xx_LOCALE_WORLD:
601 case BCM43xx_LOCALE_ALL:
602 return "XX";
603 case BCM43xx_LOCALE_THAILAND:
604 return "TH";
605 case BCM43xx_LOCALE_ISRAEL:
606 return "IL";
607 case BCM43xx_LOCALE_JORDAN:
608 return "JO";
609 case BCM43xx_LOCALE_CHINA:
610 return "CN";
611 case BCM43xx_LOCALE_JAPAN:
612 case BCM43xx_LOCALE_JAPAN_HIGH:
613 return "JP";
614 case BCM43xx_LOCALE_USA_CANADA_ANZ:
615 case BCM43xx_LOCALE_USA_LOW:
616 return "US";
617 case BCM43xx_LOCALE_EUROPE:
618 return "EU";
619 case BCM43xx_LOCALE_NONE:
620 return " ";
621 }
622 assert(0);
623 return " ";
624}
625
626static const char * bcm43xx_locale_string(u8 locale)
627{
628 switch (locale) {
629 case BCM43xx_LOCALE_WORLD:
630 return "World";
631 case BCM43xx_LOCALE_THAILAND:
632 return "Thailand";
633 case BCM43xx_LOCALE_ISRAEL:
634 return "Israel";
635 case BCM43xx_LOCALE_JORDAN:
636 return "Jordan";
637 case BCM43xx_LOCALE_CHINA:
638 return "China";
639 case BCM43xx_LOCALE_JAPAN:
640 return "Japan";
641 case BCM43xx_LOCALE_USA_CANADA_ANZ:
642 return "USA/Canada/ANZ";
643 case BCM43xx_LOCALE_EUROPE:
644 return "Europe";
645 case BCM43xx_LOCALE_USA_LOW:
646 return "USAlow";
647 case BCM43xx_LOCALE_JAPAN_HIGH:
648 return "JapanHigh";
649 case BCM43xx_LOCALE_ALL:
650 return "All";
651 case BCM43xx_LOCALE_NONE:
652 return "None";
653 }
654 assert(0);
655 return "";
656}
657
658static inline u8 bcm43xx_crc8(u8 crc, u8 data)
659{
660 static const u8 t[] = {
661 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
662 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
663 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
664 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
665 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
666 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
667 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
668 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
669 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
670 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
671 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
672 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
673 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
674 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
675 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
676 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
677 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
678 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
679 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
680 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
681 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
682 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
683 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
684 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
685 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
686 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
687 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
688 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
689 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
690 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
691 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
692 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
693 };
694 return t[crc ^ data];
695}
696
Michael Bueschad3f0862006-02-19 14:12:22 +0100697static u8 bcm43xx_sprom_crc(const u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500698{
699 int word;
700 u8 crc = 0xFF;
701
702 for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
703 crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
704 crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
705 }
706 crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
707 crc ^= 0xFF;
708
709 return crc;
710}
711
Michael Bueschea0922b2006-02-19 14:09:20 +0100712int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
John W. Linvillef2223132006-01-23 16:59:58 -0500713{
714 int i;
Michael Bueschea0922b2006-02-19 14:09:20 +0100715 u8 crc, expected_crc;
716
717 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
718 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
719 /* CRC-8 check. */
720 crc = bcm43xx_sprom_crc(sprom);
721 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
722 if (crc != expected_crc) {
723 printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
724 "(0x%02X, expected: 0x%02X)\n",
725 crc, expected_crc);
726 return -EINVAL;
727 }
728
729 return 0;
730}
731
732int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
733{
734 int i, err;
735 u8 crc, expected_crc;
736 u32 spromctl;
737
738 /* CRC-8 validation of the input data. */
739 crc = bcm43xx_sprom_crc(sprom);
740 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
741 if (crc != expected_crc) {
742 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
743 return -EINVAL;
744 }
745
746 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
747 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
748 if (err)
749 goto err_ctlreg;
750 spromctl |= 0x10; /* SPROM WRITE enable. */
751 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
752 if (err)
753 goto err_ctlreg;
754 /* We must burn lots of CPU cycles here, but that does not
755 * really matter as one does not write the SPROM every other minute...
756 */
757 printk(KERN_INFO PFX "[ 0%%");
758 mdelay(500);
759 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
760 if (i == 16)
761 printk("25%%");
762 else if (i == 32)
763 printk("50%%");
764 else if (i == 48)
765 printk("75%%");
766 else if (i % 2)
767 printk(".");
768 bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
Michael Bueschefccb642006-03-11 13:39:14 +0100769 mmiowb();
Michael Bueschea0922b2006-02-19 14:09:20 +0100770 mdelay(20);
771 }
772 spromctl &= ~0x10; /* SPROM WRITE enable. */
773 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
774 if (err)
775 goto err_ctlreg;
776 mdelay(500);
777 printk("100%% ]\n");
778 printk(KERN_INFO PFX "SPROM written.\n");
779 bcm43xx_controller_restart(bcm, "SPROM update");
780
781 return 0;
782err_ctlreg:
783 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
784 return -ENODEV;
785}
786
787static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
788{
John W. Linvillef2223132006-01-23 16:59:58 -0500789 u16 value;
790 u16 *sprom;
John W. Linvillef2223132006-01-23 16:59:58 -0500791#ifdef CONFIG_BCM947XX
792 char *c;
793#endif
794
795 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
796 GFP_KERNEL);
797 if (!sprom) {
Michael Bueschea0922b2006-02-19 14:09:20 +0100798 printk(KERN_ERR PFX "sprom_extract OOM\n");
John W. Linvillef2223132006-01-23 16:59:58 -0500799 return -ENOMEM;
800 }
801#ifdef CONFIG_BCM947XX
802 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
803 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
804
805 if ((c = nvram_get("il0macaddr")) != NULL)
806 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
807
808 if ((c = nvram_get("et1macaddr")) != NULL)
809 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
810
811 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
812 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
813 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
814
815 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
816 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
817 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
818
819 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
820#else
Michael Bueschea0922b2006-02-19 14:09:20 +0100821 bcm43xx_sprom_read(bcm, sprom);
John W. Linvillef2223132006-01-23 16:59:58 -0500822#endif
823
824 /* boardflags2 */
825 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
826 bcm->sprom.boardflags2 = value;
827
828 /* il0macaddr */
829 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
830 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
831 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
832 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
833 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
834 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
835
836 /* et0macaddr */
837 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
838 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
839 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
840 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
841 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
842 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
843
844 /* et1macaddr */
845 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
846 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
847 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
848 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
849 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
850 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
851
852 /* ethernet phy settings */
853 value = sprom[BCM43xx_SPROM_ETHPHY];
854 bcm->sprom.et0phyaddr = (value & 0x001F);
855 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
856 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
857 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
858
859 /* boardrev, antennas, locale */
860 value = sprom[BCM43xx_SPROM_BOARDREV];
861 bcm->sprom.boardrev = (value & 0x00FF);
862 bcm->sprom.locale = (value & 0x0F00) >> 8;
863 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
864 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
865 if (modparam_locale != -1) {
866 if (modparam_locale >= 0 && modparam_locale <= 11) {
867 bcm->sprom.locale = modparam_locale;
868 printk(KERN_WARNING PFX "Operating with modified "
869 "LocaleCode %u (%s)\n",
870 bcm->sprom.locale,
871 bcm43xx_locale_string(bcm->sprom.locale));
872 } else {
873 printk(KERN_WARNING PFX "Module parameter \"locale\" "
874 "invalid value. (0 - 11)\n");
875 }
876 }
877
878 /* pa0b* */
879 value = sprom[BCM43xx_SPROM_PA0B0];
880 bcm->sprom.pa0b0 = value;
881 value = sprom[BCM43xx_SPROM_PA0B1];
882 bcm->sprom.pa0b1 = value;
883 value = sprom[BCM43xx_SPROM_PA0B2];
884 bcm->sprom.pa0b2 = value;
885
886 /* wl0gpio* */
887 value = sprom[BCM43xx_SPROM_WL0GPIO0];
888 if (value == 0x0000)
889 value = 0xFFFF;
890 bcm->sprom.wl0gpio0 = value & 0x00FF;
891 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
892 value = sprom[BCM43xx_SPROM_WL0GPIO2];
893 if (value == 0x0000)
894 value = 0xFFFF;
895 bcm->sprom.wl0gpio2 = value & 0x00FF;
896 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
897
898 /* maxpower */
899 value = sprom[BCM43xx_SPROM_MAXPWR];
900 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
901 bcm->sprom.maxpower_bgphy = value & 0x00FF;
902
903 /* pa1b* */
904 value = sprom[BCM43xx_SPROM_PA1B0];
905 bcm->sprom.pa1b0 = value;
906 value = sprom[BCM43xx_SPROM_PA1B1];
907 bcm->sprom.pa1b1 = value;
908 value = sprom[BCM43xx_SPROM_PA1B2];
909 bcm->sprom.pa1b2 = value;
910
911 /* idle tssi target */
912 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
913 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
914 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
915
916 /* boardflags */
917 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
918 if (value == 0xFFFF)
919 value = 0x0000;
920 bcm->sprom.boardflags = value;
Michael Bueschb3db5e52006-03-15 16:31:45 +0100921 /* boardflags workarounds */
922 if (bcm->board_vendor == PCI_VENDOR_ID_DELL &&
923 bcm->chip_id == 0x4301 &&
924 bcm->board_revision == 0x74)
925 bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST;
926 if (bcm->board_vendor == PCI_VENDOR_ID_APPLE &&
927 bcm->board_type == 0x4E &&
928 bcm->board_revision > 0x40)
929 bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL;
John W. Linvillef2223132006-01-23 16:59:58 -0500930
931 /* antenna gain */
932 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
933 if (value == 0x0000 || value == 0xFFFF)
934 value = 0x0202;
935 /* convert values to Q5.2 */
936 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
937 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
938
939 kfree(sprom);
940
941 return 0;
942}
943
Michael Buesch869aaab2006-05-05 17:23:51 +0200944static int bcm43xx_geo_init(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -0500945{
Michael Buesch869aaab2006-05-05 17:23:51 +0200946 struct ieee80211_geo *geo;
John W. Linvillef2223132006-01-23 16:59:58 -0500947 struct ieee80211_channel *chan;
948 int have_a = 0, have_bg = 0;
Michael Buesche9357c02006-03-13 19:27:34 +0100949 int i;
Michael Buesch9e4a3752006-02-02 18:43:25 +0100950 u8 channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500951 struct bcm43xx_phyinfo *phy;
952 const char *iso_country;
953
Michael Buesch869aaab2006-05-05 17:23:51 +0200954 geo = kzalloc(sizeof(*geo), GFP_KERNEL);
955 if (!geo)
956 return -ENOMEM;
957
Michael Buesche9357c02006-03-13 19:27:34 +0100958 for (i = 0; i < bcm->nr_80211_available; i++) {
959 phy = &(bcm->core_80211_ext[i].phy);
John W. Linvillef2223132006-01-23 16:59:58 -0500960 switch (phy->type) {
961 case BCM43xx_PHYTYPE_B:
962 case BCM43xx_PHYTYPE_G:
963 have_bg = 1;
964 break;
965 case BCM43xx_PHYTYPE_A:
966 have_a = 1;
967 break;
968 default:
969 assert(0);
970 }
971 }
972 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
973
974 if (have_a) {
Michael Buesch869aaab2006-05-05 17:23:51 +0200975 for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL;
976 channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) {
977 chan = &geo->a[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100978 chan->freq = bcm43xx_channel_to_freq_a(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500979 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500980 }
Michael Buesch869aaab2006-05-05 17:23:51 +0200981 geo->a_channels = i;
John W. Linvillef2223132006-01-23 16:59:58 -0500982 }
983 if (have_bg) {
Michael Buesch869aaab2006-05-05 17:23:51 +0200984 for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL;
985 channel <= IEEE80211_24GHZ_MAX_CHANNEL; channel++) {
986 chan = &geo->bg[i++];
Michael Buesch10d8dd82006-02-19 22:08:48 +0100987 chan->freq = bcm43xx_channel_to_freq_bg(channel);
John W. Linvillef2223132006-01-23 16:59:58 -0500988 chan->channel = channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500989 }
Michael Buesch869aaab2006-05-05 17:23:51 +0200990 geo->bg_channels = i;
John W. Linvillef2223132006-01-23 16:59:58 -0500991 }
Michael Buesch869aaab2006-05-05 17:23:51 +0200992 memcpy(geo->name, iso_country, 2);
John W. Linvillef2223132006-01-23 16:59:58 -0500993 if (0 /*TODO: Outdoor use only */)
Michael Buesch869aaab2006-05-05 17:23:51 +0200994 geo->name[2] = 'O';
John W. Linvillef2223132006-01-23 16:59:58 -0500995 else if (0 /*TODO: Indoor use only */)
Michael Buesch869aaab2006-05-05 17:23:51 +0200996 geo->name[2] = 'I';
John W. Linvillef2223132006-01-23 16:59:58 -0500997 else
Michael Buesch869aaab2006-05-05 17:23:51 +0200998 geo->name[2] = ' ';
999 geo->name[3] = '\0';
John W. Linvillef2223132006-01-23 16:59:58 -05001000
Michael Buesch869aaab2006-05-05 17:23:51 +02001001 ieee80211_set_geo(bcm->ieee, geo);
1002 kfree(geo);
1003
1004 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05001005}
1006
1007/* DummyTransmission function, as documented on
1008 * http://bcm-specs.sipsolutions.net/DummyTransmission
1009 */
1010void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
1011{
Michael Buesche9357c02006-03-13 19:27:34 +01001012 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1013 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001014 unsigned int i, max_loop;
1015 u16 value = 0;
1016 u32 buffer[5] = {
1017 0x00000000,
1018 0x0000D400,
1019 0x00000000,
1020 0x00000001,
1021 0x00000000,
1022 };
1023
Michael Buesch489423c2006-02-13 00:11:07 +01001024 switch (phy->type) {
John W. Linvillef2223132006-01-23 16:59:58 -05001025 case BCM43xx_PHYTYPE_A:
1026 max_loop = 0x1E;
1027 buffer[0] = 0xCC010200;
1028 break;
1029 case BCM43xx_PHYTYPE_B:
1030 case BCM43xx_PHYTYPE_G:
1031 max_loop = 0xFA;
1032 buffer[0] = 0x6E840B00;
1033 break;
1034 default:
1035 assert(0);
1036 return;
1037 }
1038
1039 for (i = 0; i < 5; i++)
1040 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1041
1042 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1043
1044 bcm43xx_write16(bcm, 0x0568, 0x0000);
1045 bcm43xx_write16(bcm, 0x07C0, 0x0000);
Michael Buesch489423c2006-02-13 00:11:07 +01001046 bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
John W. Linvillef2223132006-01-23 16:59:58 -05001047 bcm43xx_write16(bcm, 0x0508, 0x0000);
1048 bcm43xx_write16(bcm, 0x050A, 0x0000);
1049 bcm43xx_write16(bcm, 0x054C, 0x0000);
1050 bcm43xx_write16(bcm, 0x056A, 0x0014);
1051 bcm43xx_write16(bcm, 0x0568, 0x0826);
1052 bcm43xx_write16(bcm, 0x0500, 0x0000);
1053 bcm43xx_write16(bcm, 0x0502, 0x0030);
1054
Michael Buesch73733842006-03-12 19:44:29 +01001055 if (radio->version == 0x2050 && radio->revision <= 0x5)
1056 bcm43xx_radio_write16(bcm, 0x0051, 0x0017);
John W. Linvillef2223132006-01-23 16:59:58 -05001057 for (i = 0x00; i < max_loop; i++) {
1058 value = bcm43xx_read16(bcm, 0x050E);
Michael Buesch73733842006-03-12 19:44:29 +01001059 if (value & 0x0080)
John W. Linvillef2223132006-01-23 16:59:58 -05001060 break;
1061 udelay(10);
1062 }
1063 for (i = 0x00; i < 0x0A; i++) {
1064 value = bcm43xx_read16(bcm, 0x050E);
Michael Buesch73733842006-03-12 19:44:29 +01001065 if (value & 0x0400)
John W. Linvillef2223132006-01-23 16:59:58 -05001066 break;
1067 udelay(10);
1068 }
1069 for (i = 0x00; i < 0x0A; i++) {
1070 value = bcm43xx_read16(bcm, 0x0690);
Michael Buesch73733842006-03-12 19:44:29 +01001071 if (!(value & 0x0100))
John W. Linvillef2223132006-01-23 16:59:58 -05001072 break;
1073 udelay(10);
1074 }
Michael Buesch73733842006-03-12 19:44:29 +01001075 if (radio->version == 0x2050 && radio->revision <= 0x5)
1076 bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
John W. Linvillef2223132006-01-23 16:59:58 -05001077}
1078
1079static void key_write(struct bcm43xx_private *bcm,
1080 u8 index, u8 algorithm, const u16 *key)
1081{
1082 unsigned int i, basic_wep = 0;
1083 u32 offset;
1084 u16 value;
1085
1086 /* Write associated key information */
1087 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1088 ((index << 4) | (algorithm & 0x0F)));
1089
1090 /* The first 4 WEP keys need extra love */
1091 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1092 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1093 basic_wep = 1;
1094
1095 /* Write key payload, 8 little endian words */
1096 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1097 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1098 value = cpu_to_le16(key[i]);
1099 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1100 offset + (i * 2), value);
1101
1102 if (!basic_wep)
1103 continue;
1104
1105 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1106 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1107 value);
1108 }
1109}
1110
1111static void keymac_write(struct bcm43xx_private *bcm,
1112 u8 index, const u32 *addr)
1113{
1114 /* for keys 0-3 there is no associated mac address */
1115 if (index < 4)
1116 return;
1117
1118 index -= 4;
1119 if (bcm->current_core->rev >= 5) {
1120 bcm43xx_shm_write32(bcm,
1121 BCM43xx_SHM_HWMAC,
1122 index * 2,
1123 cpu_to_be32(*addr));
1124 bcm43xx_shm_write16(bcm,
1125 BCM43xx_SHM_HWMAC,
1126 (index * 2) + 1,
1127 cpu_to_be16(*((u16 *)(addr + 1))));
1128 } else {
1129 if (index < 8) {
1130 TODO(); /* Put them in the macaddress filter */
1131 } else {
1132 TODO();
1133 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1134 Keep in mind to update the count of keymacs in 0x003E as well! */
1135 }
1136 }
1137}
1138
1139static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1140 u8 index, u8 algorithm,
1141 const u8 *_key, int key_len,
1142 const u8 *mac_addr)
1143{
1144 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1145
1146 if (index >= ARRAY_SIZE(bcm->key))
1147 return -EINVAL;
1148 if (key_len > ARRAY_SIZE(key))
1149 return -EINVAL;
1150 if (algorithm < 1 || algorithm > 5)
1151 return -EINVAL;
1152
1153 memcpy(key, _key, key_len);
1154 key_write(bcm, index, algorithm, (const u16 *)key);
1155 keymac_write(bcm, index, (const u32 *)mac_addr);
1156
1157 bcm->key[index].algorithm = algorithm;
1158
1159 return 0;
1160}
1161
1162static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1163{
1164 static const u32 zero_mac[2] = { 0 };
1165 unsigned int i,j, nr_keys = 54;
1166 u16 offset;
1167
1168 if (bcm->current_core->rev < 5)
1169 nr_keys = 16;
1170 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1171
1172 for (i = 0; i < nr_keys; i++) {
1173 bcm->key[i].enabled = 0;
1174 /* returns for i < 4 immediately */
1175 keymac_write(bcm, i, zero_mac);
1176 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1177 0x100 + (i * 2), 0x0000);
1178 for (j = 0; j < 8; j++) {
1179 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1180 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1181 offset, 0x0000);
1182 }
1183 }
1184 dprintk(KERN_INFO PFX "Keys cleared\n");
1185}
1186
John W. Linvillef2223132006-01-23 16:59:58 -05001187/* Lowlevel core-switch function. This is only to be used in
1188 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1189 */
1190static int _switch_core(struct bcm43xx_private *bcm, int core)
1191{
1192 int err;
1193 int attempts = 0;
Michael Buesch489423c2006-02-13 00:11:07 +01001194 u32 current_core;
John W. Linvillef2223132006-01-23 16:59:58 -05001195
1196 assert(core >= 0);
Michael Buesch489423c2006-02-13 00:11:07 +01001197 while (1) {
1198 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
John W. Linvillef2223132006-01-23 16:59:58 -05001199 (core * 0x1000) + 0x18000000);
Michael Buesch489423c2006-02-13 00:11:07 +01001200 if (unlikely(err))
1201 goto error;
1202 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1203 &current_core);
1204 if (unlikely(err))
1205 goto error;
1206 current_core = (current_core - 0x18000000) / 0x1000;
1207 if (current_core == core)
1208 break;
John W. Linvillef2223132006-01-23 16:59:58 -05001209
Michael Buesch489423c2006-02-13 00:11:07 +01001210 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
1211 goto error;
1212 udelay(10);
1213 }
1214#ifdef CONFIG_BCM947XX
1215 if (bcm->pci_dev->bus->number == 0)
1216 bcm->current_core_offset = 0x1000 * core;
1217 else
1218 bcm->current_core_offset = 0;
1219#endif
1220
1221 return 0;
1222error:
1223 printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
1224 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05001225}
1226
1227int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1228{
1229 int err;
1230
Michael Buesch489423c2006-02-13 00:11:07 +01001231 if (unlikely(!new_core))
John W. Linvillef2223132006-01-23 16:59:58 -05001232 return 0;
Michael Buesche9357c02006-03-13 19:27:34 +01001233 if (!new_core->available)
John W. Linvillef2223132006-01-23 16:59:58 -05001234 return -ENODEV;
1235 if (bcm->current_core == new_core)
1236 return 0;
1237 err = _switch_core(bcm, new_core->index);
Michael Buesche9357c02006-03-13 19:27:34 +01001238 if (unlikely(err))
1239 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001240
Michael Buesche9357c02006-03-13 19:27:34 +01001241 bcm->current_core = new_core;
1242 bcm->current_80211_core_idx = -1;
1243 if (new_core->id == BCM43xx_COREID_80211)
1244 bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
1245
1246out:
John W. Linvillef2223132006-01-23 16:59:58 -05001247 return err;
1248}
1249
Michael Buesch489423c2006-02-13 00:11:07 +01001250static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001251{
1252 u32 value;
1253
1254 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1255 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1256 | BCM43xx_SBTMSTATELOW_REJECT;
1257
1258 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1259}
1260
1261/* disable current core */
1262static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1263{
1264 u32 sbtmstatelow;
1265 u32 sbtmstatehigh;
1266 int i;
1267
1268 /* fetch sbtmstatelow from core information registers */
1269 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1270
1271 /* core is already in reset */
1272 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1273 goto out;
1274
1275 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1276 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1277 BCM43xx_SBTMSTATELOW_REJECT;
1278 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1279
1280 for (i = 0; i < 1000; i++) {
1281 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1282 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1283 i = -1;
1284 break;
1285 }
1286 udelay(10);
1287 }
1288 if (i != -1) {
1289 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1290 return -EBUSY;
1291 }
1292
1293 for (i = 0; i < 1000; i++) {
1294 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1295 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1296 i = -1;
1297 break;
1298 }
1299 udelay(10);
1300 }
1301 if (i != -1) {
1302 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1303 return -EBUSY;
1304 }
1305
1306 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1307 BCM43xx_SBTMSTATELOW_REJECT |
1308 BCM43xx_SBTMSTATELOW_RESET |
1309 BCM43xx_SBTMSTATELOW_CLOCK |
1310 core_flags;
1311 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1312 udelay(10);
1313 }
1314
1315 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1316 BCM43xx_SBTMSTATELOW_REJECT |
1317 core_flags;
1318 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1319
1320out:
Michael Buesche9357c02006-03-13 19:27:34 +01001321 bcm->current_core->enabled = 0;
1322
John W. Linvillef2223132006-01-23 16:59:58 -05001323 return 0;
1324}
1325
1326/* enable (reset) current core */
1327static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1328{
1329 u32 sbtmstatelow;
1330 u32 sbtmstatehigh;
1331 u32 sbimstate;
1332 int err;
1333
1334 err = bcm43xx_core_disable(bcm, core_flags);
1335 if (err)
1336 goto out;
1337
1338 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1339 BCM43xx_SBTMSTATELOW_RESET |
1340 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1341 core_flags;
1342 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1343 udelay(1);
1344
1345 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1346 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1347 sbtmstatehigh = 0x00000000;
1348 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1349 }
1350
1351 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1352 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1353 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1354 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1355 }
1356
1357 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1358 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1359 core_flags;
1360 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1361 udelay(1);
1362
1363 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1364 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1365 udelay(1);
1366
Michael Buesche9357c02006-03-13 19:27:34 +01001367 bcm->current_core->enabled = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001368 assert(err == 0);
1369out:
1370 return err;
1371}
1372
1373/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1374void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1375{
1376 u32 flags = 0x00040000;
1377
Michael Buesch77db31e2006-02-12 16:47:44 +01001378 if ((bcm43xx_core_enabled(bcm)) &&
1379 !bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05001380//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1381#ifndef CONFIG_BCM947XX
1382 /* reset all used DMA controllers. */
1383 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1384 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1385 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1386 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1387 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1388 if (bcm->current_core->rev < 5)
1389 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1390#endif
1391 }
Michael Buesch78ff56a2006-06-05 20:24:10 +02001392 if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
John W. Linvillef2223132006-01-23 16:59:58 -05001393 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1394 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1395 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1396 } else {
1397 if (connect_phy)
1398 flags |= 0x20000000;
1399 bcm43xx_phy_connect(bcm, connect_phy);
1400 bcm43xx_core_enable(bcm, flags);
1401 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1402 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1403 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1404 | BCM43xx_SBF_400);
1405 }
1406}
1407
1408static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1409{
1410 bcm43xx_radio_turn_off(bcm);
1411 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1412 bcm43xx_core_disable(bcm, 0);
1413}
1414
1415/* Mark the current 80211 core inactive.
1416 * "active_80211_core" is the other 80211 core, which is used.
1417 */
1418static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1419 struct bcm43xx_coreinfo *active_80211_core)
1420{
1421 u32 sbtmstatelow;
1422 struct bcm43xx_coreinfo *old_core;
1423 int err = 0;
1424
1425 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1426 bcm43xx_radio_turn_off(bcm);
1427 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1428 sbtmstatelow &= ~0x200a0000;
1429 sbtmstatelow |= 0xa0000;
1430 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1431 udelay(1);
1432 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1433 sbtmstatelow &= ~0xa0000;
1434 sbtmstatelow |= 0x80000;
1435 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1436 udelay(1);
1437
Michael Buesche9357c02006-03-13 19:27:34 +01001438 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -05001439 old_core = bcm->current_core;
1440 err = bcm43xx_switch_core(bcm, active_80211_core);
1441 if (err)
1442 goto out;
1443 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1444 sbtmstatelow &= ~0x20000000;
1445 sbtmstatelow |= 0x20000000;
1446 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1447 err = bcm43xx_switch_core(bcm, old_core);
1448 }
1449
1450out:
1451 return err;
1452}
1453
Michael Buesch489423c2006-02-13 00:11:07 +01001454static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001455{
1456 u32 v0, v1;
1457 u16 tmp;
1458 struct bcm43xx_xmitstatus stat;
1459
John W. Linvillef2223132006-01-23 16:59:58 -05001460 while (1) {
1461 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1462 if (!v0)
1463 break;
1464 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1465
1466 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1467 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1468 stat.flags = tmp & 0xFF;
1469 stat.cnt1 = (tmp & 0x0F00) >> 8;
1470 stat.cnt2 = (tmp & 0xF000) >> 12;
1471 stat.seq = (u16)(v1 & 0xFFFF);
1472 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1473
1474 bcm43xx_debugfs_log_txstat(bcm, &stat);
1475
1476 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1477 continue;
1478 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1479 //TODO: packet was not acked (was lost)
1480 }
1481 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1482
Michael Buesch77db31e2006-02-12 16:47:44 +01001483 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05001484 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1485 else
1486 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1487 }
1488}
1489
Michael Buesch489423c2006-02-13 00:11:07 +01001490static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001491{
1492 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1493 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1494 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1495 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1496 assert(bcm->noisecalc.core_at_start == bcm->current_core);
Michael Buesche9357c02006-03-13 19:27:34 +01001497 assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);
John W. Linvillef2223132006-01-23 16:59:58 -05001498}
1499
1500static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1501{
1502 /* Top half of Link Quality calculation. */
1503
1504 if (bcm->noisecalc.calculation_running)
1505 return;
1506 bcm->noisecalc.core_at_start = bcm->current_core;
Michael Buesche9357c02006-03-13 19:27:34 +01001507 bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;
John W. Linvillef2223132006-01-23 16:59:58 -05001508 bcm->noisecalc.calculation_running = 1;
1509 bcm->noisecalc.nr_samples = 0;
1510
1511 bcm43xx_generate_noise_sample(bcm);
1512}
1513
Michael Buesch489423c2006-02-13 00:11:07 +01001514static void handle_irq_noise(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001515{
Michael Buesche9357c02006-03-13 19:27:34 +01001516 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001517 u16 tmp;
1518 u8 noise[4];
1519 u8 i, j;
1520 s32 average;
1521
1522 /* Bottom half of Link Quality calculation. */
1523
1524 assert(bcm->noisecalc.calculation_running);
1525 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1526 bcm->noisecalc.channel_at_start != radio->channel)
1527 goto drop_calculation;
1528 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1529 noise[0] = (tmp & 0x00FF);
1530 noise[1] = (tmp & 0xFF00) >> 8;
1531 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1532 noise[2] = (tmp & 0x00FF);
1533 noise[3] = (tmp & 0xFF00) >> 8;
1534 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1535 noise[2] == 0x7F || noise[3] == 0x7F)
1536 goto generate_new;
1537
1538 /* Get the noise samples. */
1539 assert(bcm->noisecalc.nr_samples <= 8);
1540 i = bcm->noisecalc.nr_samples;
1541 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1542 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1543 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1544 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1545 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1546 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1547 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1548 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1549 bcm->noisecalc.nr_samples++;
1550 if (bcm->noisecalc.nr_samples == 8) {
1551 /* Calculate the Link Quality by the noise samples. */
1552 average = 0;
1553 for (i = 0; i < 8; i++) {
1554 for (j = 0; j < 4; j++)
1555 average += bcm->noisecalc.samples[i][j];
1556 }
1557 average /= (8 * 4);
1558 average *= 125;
1559 average += 64;
1560 average /= 128;
Michael Buesch72fb8512006-03-22 18:10:19 +01001561
John W. Linvillef2223132006-01-23 16:59:58 -05001562 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1563 tmp = (tmp / 128) & 0x1F;
1564 if (tmp >= 8)
1565 average += 2;
1566 else
1567 average -= 25;
1568 if (tmp == 8)
1569 average -= 72;
1570 else
1571 average -= 48;
1572
Michael Buesch72fb8512006-03-22 18:10:19 +01001573/* FIXME: This is wrong, but people want fancy stats. well... */
1574bcm->stats.noise = average;
John W. Linvillef2223132006-01-23 16:59:58 -05001575 if (average > -65)
1576 bcm->stats.link_quality = 0;
1577 else if (average > -75)
1578 bcm->stats.link_quality = 1;
1579 else if (average > -85)
1580 bcm->stats.link_quality = 2;
1581 else
1582 bcm->stats.link_quality = 3;
1583// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1584drop_calculation:
1585 bcm->noisecalc.calculation_running = 0;
1586 return;
1587 }
1588generate_new:
1589 bcm43xx_generate_noise_sample(bcm);
1590}
1591
Michael Buesch489423c2006-02-13 00:11:07 +01001592static void handle_irq_ps(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001593{
1594 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1595 ///TODO: PS TBTT
1596 } else {
1597 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1598 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1599 }
1600 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1601 bcm->reg124_set_0x4 = 1;
1602 //FIXME else set to false?
1603}
1604
Michael Buesch489423c2006-02-13 00:11:07 +01001605static void handle_irq_reg124(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001606{
1607 if (!bcm->reg124_set_0x4)
1608 return;
1609 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1610 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1611 | 0x4);
1612 //FIXME: reset reg124_set_0x4 to false?
1613}
1614
Michael Buesch489423c2006-02-13 00:11:07 +01001615static void handle_irq_pmq(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001616{
1617 u32 tmp;
1618
1619 //TODO: AP mode.
1620
1621 while (1) {
1622 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1623 if (!(tmp & 0x00000008))
1624 break;
1625 }
1626 /* 16bit write is odd, but correct. */
1627 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1628}
1629
1630static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1631 u16 ram_offset, u16 shm_size_offset)
1632{
1633 u32 value;
1634 u16 size = 0;
1635
1636 /* Timestamp. */
1637 //FIXME: assumption: The chip sets the timestamp
1638 value = 0;
1639 bcm43xx_ram_write(bcm, ram_offset++, value);
1640 bcm43xx_ram_write(bcm, ram_offset++, value);
1641 size += 8;
1642
1643 /* Beacon Interval / Capability Information */
1644 value = 0x0000;//FIXME: Which interval?
1645 value |= (1 << 0) << 16; /* ESS */
1646 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1647 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1648 if (!bcm->ieee->open_wep)
1649 value |= (1 << 4) << 16; /* Privacy */
1650 bcm43xx_ram_write(bcm, ram_offset++, value);
1651 size += 4;
1652
1653 /* SSID */
1654 //TODO
1655
1656 /* FH Parameter Set */
1657 //TODO
1658
1659 /* DS Parameter Set */
1660 //TODO
1661
1662 /* CF Parameter Set */
1663 //TODO
1664
1665 /* TIM */
1666 //TODO
1667
1668 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1669}
1670
Michael Buesch489423c2006-02-13 00:11:07 +01001671static void handle_irq_beacon(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05001672{
1673 u32 status;
1674
1675 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1676 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1677
1678 if ((status & 0x1) && (status & 0x2)) {
1679 /* ACK beacon IRQ. */
1680 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1681 BCM43xx_IRQ_BEACON);
1682 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1683 return;
1684 }
1685 if (!(status & 0x1)) {
1686 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
1687 status |= 0x1;
1688 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1689 }
1690 if (!(status & 0x2)) {
1691 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
1692 status |= 0x2;
1693 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1694 }
1695}
1696
John W. Linvillef2223132006-01-23 16:59:58 -05001697/* Interrupt handler bottom-half */
1698static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
1699{
1700 u32 reason;
1701 u32 dma_reason[4];
1702 int activity = 0;
1703 unsigned long flags;
1704
1705#ifdef CONFIG_BCM43XX_DEBUG
1706 u32 _handled = 0x00000000;
1707# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
1708#else
1709# define bcmirq_handled(irq) do { /* nothing */ } while (0)
1710#endif /* CONFIG_BCM43XX_DEBUG*/
1711
Michael Buesch78ff56a2006-06-05 20:24:10 +02001712 bcm43xx_lock_irqonly(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001713 reason = bcm->irq_reason;
1714 dma_reason[0] = bcm->dma_reason[0];
1715 dma_reason[1] = bcm->dma_reason[1];
1716 dma_reason[2] = bcm->dma_reason[2];
1717 dma_reason[3] = bcm->dma_reason[3];
1718
1719 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
1720 /* TX error. We get this when Template Ram is written in wrong endianess
1721 * in dummy_tx(). We also get this if something is wrong with the TX header
1722 * on DMA or PIO queues.
1723 * Maybe we get this in other error conditions, too.
1724 */
Michael Buesch73733842006-03-12 19:44:29 +01001725 printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
John W. Linvillef2223132006-01-23 16:59:58 -05001726 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
1727 }
Michael Buesch73733842006-03-12 19:44:29 +01001728 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
1729 (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
1730 (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
1731 (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
1732 printkl(KERN_ERR PFX "FATAL ERROR: Fatal 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 bcm43xx_controller_restart(bcm, "DMA error");
Michael Buesch78ff56a2006-06-05 20:24:10 +02001737 mmiowb();
1738 bcm43xx_unlock_irqonly(bcm, flags);
Michael Buesch73733842006-03-12 19:44:29 +01001739 return;
1740 }
1741 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
1742 (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
1743 (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
1744 (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
1745 printkl(KERN_ERR PFX "DMA error: "
1746 "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1747 dma_reason[0], dma_reason[1],
1748 dma_reason[2], dma_reason[3]);
1749 }
John W. Linvillef2223132006-01-23 16:59:58 -05001750
1751 if (reason & BCM43xx_IRQ_PS) {
1752 handle_irq_ps(bcm);
1753 bcmirq_handled(BCM43xx_IRQ_PS);
1754 }
1755
1756 if (reason & BCM43xx_IRQ_REG124) {
1757 handle_irq_reg124(bcm);
1758 bcmirq_handled(BCM43xx_IRQ_REG124);
1759 }
1760
1761 if (reason & BCM43xx_IRQ_BEACON) {
1762 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
1763 handle_irq_beacon(bcm);
1764 bcmirq_handled(BCM43xx_IRQ_BEACON);
1765 }
1766
1767 if (reason & BCM43xx_IRQ_PMQ) {
1768 handle_irq_pmq(bcm);
1769 bcmirq_handled(BCM43xx_IRQ_PMQ);
1770 }
1771
1772 if (reason & BCM43xx_IRQ_SCAN) {
1773 /*TODO*/
1774 //bcmirq_handled(BCM43xx_IRQ_SCAN);
1775 }
1776
1777 if (reason & BCM43xx_IRQ_NOISE) {
1778 handle_irq_noise(bcm);
1779 bcmirq_handled(BCM43xx_IRQ_NOISE);
1780 }
1781
1782 /* Check the DMA reason registers for received data. */
1783 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
1784 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
1785 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesch77db31e2006-02-12 16:47:44 +01001786 if (bcm43xx_using_pio(bcm))
Michael Buesche9357c02006-03-13 19:27:34 +01001787 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
John W. Linvillef2223132006-01-23 16:59:58 -05001788 else
Michael Buesche9357c02006-03-13 19:27:34 +01001789 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
Michael Bueschdcfd7202006-02-12 20:25:55 +01001790 /* We intentionally don't set "activity" to 1, here. */
John W. Linvillef2223132006-01-23 16:59:58 -05001791 }
1792 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
Michael Buesche1b1b582006-03-13 15:20:05 +01001793 if (bcm43xx_using_pio(bcm))
Michael Buesche9357c02006-03-13 19:27:34 +01001794 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
Michael Buesche1b1b582006-03-13 15:20:05 +01001795 else
Michael Buesche9357c02006-03-13 19:27:34 +01001796 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
Michael Buesche1b1b582006-03-13 15:20:05 +01001797 activity = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001798 }
1799 bcmirq_handled(BCM43xx_IRQ_RX);
1800
1801 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
Michael Buesche1b1b582006-03-13 15:20:05 +01001802 handle_irq_transmit_status(bcm);
1803 activity = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05001804 //TODO: In AP mode, this also causes sending of powersave responses.
1805 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
1806 }
1807
John W. Linvillef2223132006-01-23 16:59:58 -05001808 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
1809 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
1810#ifdef CONFIG_BCM43XX_DEBUG
1811 if (unlikely(reason & ~_handled)) {
1812 printkl(KERN_WARNING PFX
1813 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
1814 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1815 reason, (reason & ~_handled),
1816 dma_reason[0], dma_reason[1],
1817 dma_reason[2], dma_reason[3]);
1818 }
1819#endif
1820#undef bcmirq_handled
1821
1822 if (!modparam_noleds)
1823 bcm43xx_leds_update(bcm, activity);
1824 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
Michael Buesch78ff56a2006-06-05 20:24:10 +02001825 mmiowb();
1826 bcm43xx_unlock_irqonly(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05001827}
1828
Michael Buesch0ac59da2006-03-19 21:43:40 +01001829static void pio_irq_workaround(struct bcm43xx_private *bcm,
1830 u16 base, int queueidx)
John W. Linvillef2223132006-01-23 16:59:58 -05001831{
Michael Buesch0ac59da2006-03-19 21:43:40 +01001832 u16 rxctl;
John W. Linvillef2223132006-01-23 16:59:58 -05001833
Michael Buesch0ac59da2006-03-19 21:43:40 +01001834 rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);
1835 if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)
1836 bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;
1837 else
1838 bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;
1839}
1840
1841static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
1842{
Michael Buesch77db31e2006-02-12 16:47:44 +01001843 if (bcm43xx_using_pio(bcm) &&
John W. Linvillef2223132006-01-23 16:59:58 -05001844 (bcm->current_core->rev < 3) &&
1845 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
1846 /* Apply a PIO specific workaround to the dma_reasons */
Michael Buesch0ac59da2006-03-19 21:43:40 +01001847 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);
1848 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);
1849 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);
1850 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);
John W. Linvillef2223132006-01-23 16:59:58 -05001851 }
1852
Michael Buesch0ac59da2006-03-19 21:43:40 +01001853 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
John W. Linvillef2223132006-01-23 16:59:58 -05001854
1855 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
1856 bcm->dma_reason[0]);
1857 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
1858 bcm->dma_reason[1]);
1859 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
1860 bcm->dma_reason[2]);
1861 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
1862 bcm->dma_reason[3]);
1863}
1864
1865/* Interrupt handler top-half */
1866static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
1867{
Michael Bueschefccb642006-03-11 13:39:14 +01001868 irqreturn_t ret = IRQ_HANDLED;
John W. Linvillef2223132006-01-23 16:59:58 -05001869 struct bcm43xx_private *bcm = dev_id;
Michael Buesch0ac59da2006-03-19 21:43:40 +01001870 u32 reason;
John W. Linvillef2223132006-01-23 16:59:58 -05001871
1872 if (!bcm)
1873 return IRQ_NONE;
1874
Michael Buesch78ff56a2006-06-05 20:24:10 +02001875 spin_lock(&bcm->irq_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001876
1877 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
1878 if (reason == 0xffffffff) {
1879 /* irq not for us (shared irq) */
Michael Bueschefccb642006-03-11 13:39:14 +01001880 ret = IRQ_NONE;
1881 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001882 }
Michael Buesch0ac59da2006-03-19 21:43:40 +01001883 reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
1884 if (!reason)
Michael Bueschefccb642006-03-11 13:39:14 +01001885 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05001886
Michael Buesch0ac59da2006-03-19 21:43:40 +01001887 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
1888 & 0x0001dc00;
1889 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
1890 & 0x0000dc00;
1891 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
1892 & 0x0000dc00;
1893 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
1894 & 0x0001dc00;
1895
1896 bcm43xx_interrupt_ack(bcm, reason);
John W. Linvillef2223132006-01-23 16:59:58 -05001897
Michael Bueschbf7b8762006-02-21 17:58:18 +01001898 /* Only accept IRQs, if we are initialized properly.
1899 * This avoids an RX race while initializing.
1900 * We should probably not enable IRQs before we are initialized
1901 * completely, but some careful work is needed to fix this. I think it
1902 * is best to stay with this cheap workaround for now... .
1903 */
Michael Buesch78ff56a2006-06-05 20:24:10 +02001904 if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
Michael Bueschbf7b8762006-02-21 17:58:18 +01001905 /* disable all IRQs. They are enabled again in the bottom half. */
1906 bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1907 /* save the reason code and call our bottom half. */
1908 bcm->irq_reason = reason;
1909 tasklet_schedule(&bcm->isr_tasklet);
1910 }
John W. Linvillef2223132006-01-23 16:59:58 -05001911
Michael Bueschefccb642006-03-11 13:39:14 +01001912out:
1913 mmiowb();
Michael Buesch78ff56a2006-06-05 20:24:10 +02001914 spin_unlock(&bcm->irq_lock);
John W. Linvillef2223132006-01-23 16:59:58 -05001915
Michael Bueschefccb642006-03-11 13:39:14 +01001916 return ret;
John W. Linvillef2223132006-01-23 16:59:58 -05001917}
1918
Michael Buescha4a600d2006-02-01 22:09:52 +01001919static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
John W. Linvillef2223132006-01-23 16:59:58 -05001920{
Michael Buescha4a600d2006-02-01 22:09:52 +01001921 if (bcm->firmware_norelease && !force)
John W. Linvillef2223132006-01-23 16:59:58 -05001922 return; /* Suspending or controller reset. */
1923 release_firmware(bcm->ucode);
1924 bcm->ucode = NULL;
1925 release_firmware(bcm->pcm);
1926 bcm->pcm = NULL;
1927 release_firmware(bcm->initvals0);
1928 bcm->initvals0 = NULL;
1929 release_firmware(bcm->initvals1);
1930 bcm->initvals1 = NULL;
1931}
1932
1933static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1934{
Michael Buesche9357c02006-03-13 19:27:34 +01001935 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05001936 u8 rev = bcm->current_core->rev;
1937 int err = 0;
1938 int nr;
1939 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
1940
1941 if (!bcm->ucode) {
1942 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
1943 (rev >= 5 ? 5 : rev),
1944 modparam_fwpostfix);
1945 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
1946 if (err) {
1947 printk(KERN_ERR PFX
1948 "Error: Microcode \"%s\" not available or load failed.\n",
1949 buf);
1950 goto error;
1951 }
1952 }
1953
1954 if (!bcm->pcm) {
1955 snprintf(buf, ARRAY_SIZE(buf),
1956 "bcm43xx_pcm%d%s.fw",
1957 (rev < 5 ? 4 : 5),
1958 modparam_fwpostfix);
1959 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
1960 if (err) {
1961 printk(KERN_ERR PFX
1962 "Error: PCM \"%s\" not available or load failed.\n",
1963 buf);
1964 goto error;
1965 }
1966 }
1967
1968 if (!bcm->initvals0) {
1969 if (rev == 2 || rev == 4) {
1970 switch (phy->type) {
1971 case BCM43xx_PHYTYPE_A:
1972 nr = 3;
1973 break;
1974 case BCM43xx_PHYTYPE_B:
1975 case BCM43xx_PHYTYPE_G:
1976 nr = 1;
1977 break;
1978 default:
1979 goto err_noinitval;
1980 }
1981
1982 } else if (rev >= 5) {
1983 switch (phy->type) {
1984 case BCM43xx_PHYTYPE_A:
1985 nr = 7;
1986 break;
1987 case BCM43xx_PHYTYPE_B:
1988 case BCM43xx_PHYTYPE_G:
1989 nr = 5;
1990 break;
1991 default:
1992 goto err_noinitval;
1993 }
1994 } else
1995 goto err_noinitval;
1996 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1997 nr, modparam_fwpostfix);
1998
1999 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
2000 if (err) {
2001 printk(KERN_ERR PFX
2002 "Error: InitVals \"%s\" not available or load failed.\n",
2003 buf);
2004 goto error;
2005 }
2006 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
2007 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2008 goto error;
2009 }
2010 }
2011
2012 if (!bcm->initvals1) {
2013 if (rev >= 5) {
2014 u32 sbtmstatehigh;
2015
2016 switch (phy->type) {
2017 case BCM43xx_PHYTYPE_A:
2018 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
2019 if (sbtmstatehigh & 0x00010000)
2020 nr = 9;
2021 else
2022 nr = 10;
2023 break;
2024 case BCM43xx_PHYTYPE_B:
2025 case BCM43xx_PHYTYPE_G:
2026 nr = 6;
2027 break;
2028 default:
2029 goto err_noinitval;
2030 }
2031 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2032 nr, modparam_fwpostfix);
2033
2034 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
2035 if (err) {
2036 printk(KERN_ERR PFX
2037 "Error: InitVals \"%s\" not available or load failed.\n",
2038 buf);
2039 goto error;
2040 }
2041 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
2042 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2043 goto error;
2044 }
2045 }
2046 }
2047
2048out:
2049 return err;
2050error:
Michael Buescha4a600d2006-02-01 22:09:52 +01002051 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002052 goto out;
2053err_noinitval:
2054 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2055 err = -ENOENT;
2056 goto error;
2057}
2058
2059static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2060{
2061 const u32 *data;
2062 unsigned int i, len;
2063
John W. Linvillef2223132006-01-23 16:59:58 -05002064 /* Upload Microcode. */
2065 data = (u32 *)(bcm->ucode->data);
2066 len = bcm->ucode->size / sizeof(u32);
2067 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2068 for (i = 0; i < len; i++) {
2069 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2070 be32_to_cpu(data[i]));
2071 udelay(10);
2072 }
2073
2074 /* Upload PCM data. */
2075 data = (u32 *)(bcm->pcm->data);
2076 len = bcm->pcm->size / sizeof(u32);
2077 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2078 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2079 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2080 for (i = 0; i < len; i++) {
2081 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2082 be32_to_cpu(data[i]));
2083 udelay(10);
2084 }
John W. Linvillef2223132006-01-23 16:59:58 -05002085}
2086
Michael Buescha4a600d2006-02-01 22:09:52 +01002087static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2088 const struct bcm43xx_initval *data,
2089 const unsigned int len)
John W. Linvillef2223132006-01-23 16:59:58 -05002090{
2091 u16 offset, size;
2092 u32 value;
2093 unsigned int i;
2094
2095 for (i = 0; i < len; i++) {
2096 offset = be16_to_cpu(data[i].offset);
2097 size = be16_to_cpu(data[i].size);
2098 value = be32_to_cpu(data[i].value);
2099
Michael Buescha4a600d2006-02-01 22:09:52 +01002100 if (unlikely(offset >= 0x1000))
2101 goto err_format;
2102 if (size == 2) {
2103 if (unlikely(value & 0xFFFF0000))
2104 goto err_format;
2105 bcm43xx_write16(bcm, offset, (u16)value);
2106 } else if (size == 4) {
John W. Linvillef2223132006-01-23 16:59:58 -05002107 bcm43xx_write32(bcm, offset, value);
Michael Buescha4a600d2006-02-01 22:09:52 +01002108 } else
2109 goto err_format;
John W. Linvillef2223132006-01-23 16:59:58 -05002110 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002111
2112 return 0;
2113
2114err_format:
2115 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2116 "Please fix your bcm43xx firmware files.\n");
2117 return -EPROTO;
John W. Linvillef2223132006-01-23 16:59:58 -05002118}
2119
Michael Buescha4a600d2006-02-01 22:09:52 +01002120static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002121{
Michael Buescha4a600d2006-02-01 22:09:52 +01002122 int err;
2123
Michael Buescha4a600d2006-02-01 22:09:52 +01002124 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2125 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2126 if (err)
2127 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002128 if (bcm->initvals1) {
Michael Buescha4a600d2006-02-01 22:09:52 +01002129 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2130 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2131 if (err)
2132 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002133 }
Michael Buescha4a600d2006-02-01 22:09:52 +01002134out:
Michael Buescha4a600d2006-02-01 22:09:52 +01002135 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002136}
2137
2138static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2139{
2140 int res;
2141 unsigned int i;
2142 u32 data;
2143
2144 bcm->irq = bcm->pci_dev->irq;
2145#ifdef CONFIG_BCM947XX
2146 if (bcm->pci_dev->bus->number == 0) {
2147 struct pci_dev *d = NULL;
2148 /* FIXME: we will probably need more device IDs here... */
2149 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2150 if (d != NULL) {
2151 bcm->irq = d->irq;
2152 }
2153 }
2154#endif
2155 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
Michael Buesch65f3f192006-01-31 20:11:38 +01002156 SA_SHIRQ, KBUILD_MODNAME, bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002157 if (res) {
2158 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
Michael Buesch489423c2006-02-13 00:11:07 +01002159 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002160 }
2161 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2162 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2163 i = 0;
2164 while (1) {
2165 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2166 if (data == BCM43xx_IRQ_READY)
2167 break;
2168 i++;
2169 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2170 printk(KERN_ERR PFX "Card IRQ register not responding. "
2171 "Giving up.\n");
2172 free_irq(bcm->irq, bcm);
2173 return -ENODEV;
2174 }
2175 udelay(10);
2176 }
2177 // dummy read
2178 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2179
2180 return 0;
2181}
2182
2183/* Switch to the core used to write the GPIO register.
2184 * This is either the ChipCommon, or the PCI core.
2185 */
Michael Buesch489423c2006-02-13 00:11:07 +01002186static int switch_to_gpio_core(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05002187{
2188 int err;
2189
2190 /* Where to find the GPIO register depends on the chipset.
2191 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2192 * control register. Otherwise the register at offset 0x6c in the
2193 * PCI core is the GPIO control register.
2194 */
2195 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2196 if (err == -ENODEV) {
2197 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
Michael Buesch489423c2006-02-13 00:11:07 +01002198 if (unlikely(err == -ENODEV)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002199 printk(KERN_ERR PFX "gpio error: "
2200 "Neither ChipCommon nor PCI core available!\n");
Michael Buesch714eece2006-03-18 21:28:46 +01002201 }
2202 }
John W. Linvillef2223132006-01-23 16:59:58 -05002203
Michael Buesch714eece2006-03-18 21:28:46 +01002204 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002205}
2206
2207/* Initialize the GPIOs
2208 * http://bcm-specs.sipsolutions.net/GPIO
2209 */
2210static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2211{
2212 struct bcm43xx_coreinfo *old_core;
2213 int err;
Michael Buesch714eece2006-03-18 21:28:46 +01002214 u32 mask, set;
John W. Linvillef2223132006-01-23 16:59:58 -05002215
Michael Buesch714eece2006-03-18 21:28:46 +01002216 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2217 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2218 & 0xFFFF3FFF);
John W. Linvillef2223132006-01-23 16:59:58 -05002219
Michael Buesch714eece2006-03-18 21:28:46 +01002220 bcm43xx_leds_switch_all(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002221 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2222 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2223
Michael Buesch714eece2006-03-18 21:28:46 +01002224 mask = 0x0000001F;
2225 set = 0x0000000F;
John W. Linvillef2223132006-01-23 16:59:58 -05002226 if (bcm->chip_id == 0x4301) {
Michael Buesch714eece2006-03-18 21:28:46 +01002227 mask |= 0x0060;
2228 set |= 0x0060;
2229 }
2230 if (0 /* FIXME: conditional unknown */) {
2231 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2232 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2233 | 0x0100);
2234 mask |= 0x0180;
2235 set |= 0x0180;
John W. Linvillef2223132006-01-23 16:59:58 -05002236 }
2237 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
Michael Buesch714eece2006-03-18 21:28:46 +01002238 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2239 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2240 | 0x0200);
2241 mask |= 0x0200;
2242 set |= 0x0200;
John W. Linvillef2223132006-01-23 16:59:58 -05002243 }
Michael Buesch714eece2006-03-18 21:28:46 +01002244 if (bcm->current_core->rev >= 2)
2245 mask |= 0x0010; /* FIXME: This is redundant. */
John W. Linvillef2223132006-01-23 16:59:58 -05002246
Michael Buesch714eece2006-03-18 21:28:46 +01002247 old_core = bcm->current_core;
2248 err = switch_to_gpio_core(bcm);
2249 if (err)
2250 goto out;
John W. Linvillef2223132006-01-23 16:59:58 -05002251 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
Michael Buesch714eece2006-03-18 21:28:46 +01002252 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);
John W. Linvillef2223132006-01-23 16:59:58 -05002253 err = bcm43xx_switch_core(bcm, old_core);
Michael Buesch714eece2006-03-18 21:28:46 +01002254out:
2255 return err;
John W. Linvillef2223132006-01-23 16:59:58 -05002256}
2257
2258/* Turn off all GPIO stuff. Call this on module unload, for example. */
2259static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2260{
2261 struct bcm43xx_coreinfo *old_core;
2262 int err;
2263
2264 old_core = bcm->current_core;
2265 err = switch_to_gpio_core(bcm);
2266 if (err)
2267 return err;
2268 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2269 err = bcm43xx_switch_core(bcm, old_core);
2270 assert(err == 0);
2271
2272 return 0;
2273}
2274
2275/* http://bcm-specs.sipsolutions.net/EnableMac */
2276void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2277{
2278 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2279 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2280 | BCM43xx_SBF_MAC_ENABLED);
2281 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2282 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2283 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2284 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2285}
2286
2287/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2288void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2289{
2290 int i;
2291 u32 tmp;
2292
2293 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2294 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2295 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2296 & ~BCM43xx_SBF_MAC_ENABLED);
2297 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
Michael Buesch921e4852006-02-08 17:55:55 +01002298 for (i = 100000; i; i--) {
John W. Linvillef2223132006-01-23 16:59:58 -05002299 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch921e4852006-02-08 17:55:55 +01002300 if (tmp & BCM43xx_IRQ_READY)
2301 return;
John W. Linvillef2223132006-01-23 16:59:58 -05002302 udelay(10);
2303 }
Michael Buesch921e4852006-02-08 17:55:55 +01002304 printkl(KERN_ERR PFX "MAC suspend failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05002305}
2306
2307void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2308 int iw_mode)
2309{
2310 unsigned long flags;
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002311 struct net_device *net_dev = bcm->net_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05002312 u32 status;
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002313 u16 value;
John W. Linvillef2223132006-01-23 16:59:58 -05002314
2315 spin_lock_irqsave(&bcm->ieee->lock, flags);
2316 bcm->ieee->iw_mode = iw_mode;
2317 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2318 if (iw_mode == IW_MODE_MONITOR)
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002319 net_dev->type = ARPHRD_IEEE80211;
John W. Linvillef2223132006-01-23 16:59:58 -05002320 else
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002321 net_dev->type = ARPHRD_ETHER;
John W. Linvillef2223132006-01-23 16:59:58 -05002322
John W. Linvillef2223132006-01-23 16:59:58 -05002323 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2324 /* Reset status to infrastructured mode */
2325 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002326 status &= ~BCM43xx_SBF_MODE_PROMISC;
2327 status |= BCM43xx_SBF_MODE_NOTADHOC;
2328
2329/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */
2330status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002331
2332 switch (iw_mode) {
2333 case IW_MODE_MONITOR:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002334 status |= BCM43xx_SBF_MODE_MONITOR;
2335 status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002336 break;
2337 case IW_MODE_ADHOC:
2338 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2339 break;
2340 case IW_MODE_MASTER:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002341 status |= BCM43xx_SBF_MODE_AP;
2342 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002343 case IW_MODE_SECOND:
2344 case IW_MODE_REPEAT:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002345 TODO(); /* TODO */
John W. Linvillef2223132006-01-23 16:59:58 -05002346 break;
2347 case IW_MODE_INFRA:
2348 /* nothing to be done here... */
2349 break;
2350 default:
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002351 dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);
John W. Linvillef2223132006-01-23 16:59:58 -05002352 }
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002353 if (net_dev->flags & IFF_PROMISC)
2354 status |= BCM43xx_SBF_MODE_PROMISC;
John W. Linvillef2223132006-01-23 16:59:58 -05002355 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002356
2357 value = 0x0002;
2358 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2359 if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
2360 value = 0x0064;
2361 else
2362 value = 0x0032;
2363 }
2364 bcm43xx_write16(bcm, 0x0612, value);
John W. Linvillef2223132006-01-23 16:59:58 -05002365}
2366
2367/* This is the opposite of bcm43xx_chip_init() */
2368static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2369{
2370 bcm43xx_radio_turn_off(bcm);
2371 if (!modparam_noleds)
2372 bcm43xx_leds_exit(bcm);
2373 bcm43xx_gpio_cleanup(bcm);
2374 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002375 bcm43xx_release_firmware(bcm, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05002376}
2377
2378/* Initialize the chip
2379 * http://bcm-specs.sipsolutions.net/ChipInit
2380 */
2381static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2382{
Michael Buesche9357c02006-03-13 19:27:34 +01002383 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
2384 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002385 int err;
John W. Linvillef2223132006-01-23 16:59:58 -05002386 int tmp;
2387 u32 value32;
2388 u16 value16;
2389
2390 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2391 BCM43xx_SBF_CORE_READY
2392 | BCM43xx_SBF_400);
2393
2394 err = bcm43xx_request_firmware(bcm);
2395 if (err)
2396 goto out;
2397 bcm43xx_upload_microcode(bcm);
2398
2399 err = bcm43xx_initialize_irq(bcm);
2400 if (err)
Michael Buescha4a600d2006-02-01 22:09:52 +01002401 goto err_release_fw;
John W. Linvillef2223132006-01-23 16:59:58 -05002402
2403 err = bcm43xx_gpio_init(bcm);
2404 if (err)
2405 goto err_free_irq;
2406
Michael Buescha4a600d2006-02-01 22:09:52 +01002407 err = bcm43xx_upload_initvals(bcm);
2408 if (err)
2409 goto err_gpio_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002410 bcm43xx_radio_turn_on(bcm);
2411
John W. Linvillef2223132006-01-23 16:59:58 -05002412 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2413 err = bcm43xx_phy_init(bcm);
2414 if (err)
2415 goto err_radio_off;
2416
2417 /* Select initial Interference Mitigation. */
Michael Buesche9357c02006-03-13 19:27:34 +01002418 tmp = radio->interfmode;
2419 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
John W. Linvillef2223132006-01-23 16:59:58 -05002420 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2421
2422 bcm43xx_phy_set_antenna_diversity(bcm);
2423 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
Michael Buesche9357c02006-03-13 19:27:34 +01002424 if (phy->type == BCM43xx_PHYTYPE_B) {
John W. Linvillef2223132006-01-23 16:59:58 -05002425 value16 = bcm43xx_read16(bcm, 0x005E);
2426 value16 |= 0x0004;
2427 bcm43xx_write16(bcm, 0x005E, value16);
2428 }
2429 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2430 if (bcm->current_core->rev < 5)
2431 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2432
2433 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2434 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2435 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2436 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2437 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2438 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
John W. Linvillef2223132006-01-23 16:59:58 -05002439
John W. Linvillef2223132006-01-23 16:59:58 -05002440 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002441 value32 |= 0x100000;
John W. Linvillef2223132006-01-23 16:59:58 -05002442 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2443
Michael Buesch77db31e2006-02-12 16:47:44 +01002444 if (bcm43xx_using_pio(bcm)) {
John W. Linvillef2223132006-01-23 16:59:58 -05002445 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2446 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2447 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2448 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2449 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2450 }
2451
2452 /* Probe Response Timeout value */
2453 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2454 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2455
Michael Buesch6ab5b8e2006-03-19 17:18:48 +01002456 /* Initially set the wireless operation mode. */
2457 bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode);
John W. Linvillef2223132006-01-23 16:59:58 -05002458
2459 if (bcm->current_core->rev < 3) {
2460 bcm43xx_write16(bcm, 0x060E, 0x0000);
2461 bcm43xx_write16(bcm, 0x0610, 0x8000);
2462 bcm43xx_write16(bcm, 0x0604, 0x0000);
2463 bcm43xx_write16(bcm, 0x0606, 0x0200);
2464 } else {
2465 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2466 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2467 }
2468 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2469 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2470 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2471 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2472 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2473
2474 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2475 value32 |= 0x00100000;
2476 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2477
2478 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2479
2480 assert(err == 0);
2481 dprintk(KERN_INFO PFX "Chip initialized\n");
2482out:
2483 return err;
2484
2485err_radio_off:
2486 bcm43xx_radio_turn_off(bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002487err_gpio_cleanup:
John W. Linvillef2223132006-01-23 16:59:58 -05002488 bcm43xx_gpio_cleanup(bcm);
2489err_free_irq:
2490 free_irq(bcm->irq, bcm);
Michael Buescha4a600d2006-02-01 22:09:52 +01002491err_release_fw:
2492 bcm43xx_release_firmware(bcm, 1);
John W. Linvillef2223132006-01-23 16:59:58 -05002493 goto out;
2494}
2495
2496/* Validate chip access
2497 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2498static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2499{
John W. Linvillef2223132006-01-23 16:59:58 -05002500 u32 value;
2501 u32 shm_backup;
2502
2503 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2504 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
Michael Buesch489423c2006-02-13 00:11:07 +01002505 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2506 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002507 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
Michael Buesch489423c2006-02-13 00:11:07 +01002508 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2509 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002510 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2511
2512 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
Michael Buesch489423c2006-02-13 00:11:07 +01002513 if ((value | 0x80000000) != 0x80000400)
2514 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002515
2516 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
Michael Buesch489423c2006-02-13 00:11:07 +01002517 if (value != 0x00000000)
2518 goto error;
John W. Linvillef2223132006-01-23 16:59:58 -05002519
Michael Buesch489423c2006-02-13 00:11:07 +01002520 return 0;
2521error:
2522 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2523 return -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -05002524}
2525
Michael Buesch8afceb12006-03-25 17:04:41 +01002526static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
Michael Buesche9357c02006-03-13 19:27:34 +01002527{
2528 /* Initialize a "phyinfo" structure. The structure is already
2529 * zeroed out.
2530 */
2531 phy->antenna_diversity = 0xFFFF;
2532 phy->savedpctlreg = 0xFFFF;
2533 phy->minlowsig[0] = 0xFFFF;
2534 phy->minlowsig[1] = 0xFFFF;
2535 spin_lock_init(&phy->lock);
2536}
2537
Michael Buesch8afceb12006-03-25 17:04:41 +01002538static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
Michael Buesche9357c02006-03-13 19:27:34 +01002539{
2540 /* Initialize a "radioinfo" structure. The structure is already
2541 * zeroed out.
2542 */
2543 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2544 radio->channel = 0xFF;
2545 radio->initial_channel = 0xFF;
2546 radio->lofcal = 0xFFFF;
2547 radio->initval = 0xFFFF;
2548 radio->nrssi[0] = -1000;
2549 radio->nrssi[1] = -1000;
2550}
2551
John W. Linvillef2223132006-01-23 16:59:58 -05002552static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2553{
2554 int err, i;
2555 int current_core;
2556 u32 core_vendor, core_id, core_rev;
2557 u32 sb_id_hi, chip_id_32 = 0;
2558 u16 pci_device, chip_id_16;
2559 u8 core_count;
2560
2561 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2562 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
John W. Linvillef2223132006-01-23 16:59:58 -05002563 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2564 * BCM43xx_MAX_80211_CORES);
Michael Buesche9357c02006-03-13 19:27:34 +01002565 memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
2566 * BCM43xx_MAX_80211_CORES);
2567 bcm->current_80211_core_idx = -1;
2568 bcm->nr_80211_available = 0;
2569 bcm->current_core = NULL;
2570 bcm->active_80211_core = NULL;
John W. Linvillef2223132006-01-23 16:59:58 -05002571
2572 /* map core 0 */
2573 err = _switch_core(bcm, 0);
2574 if (err)
2575 goto out;
2576
2577 /* fetch sb_id_hi from core information registers */
2578 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2579
2580 core_id = (sb_id_hi & 0xFFF0) >> 4;
2581 core_rev = (sb_id_hi & 0xF);
2582 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2583
2584 /* if present, chipcommon is always core 0; read the chipid from it */
2585 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2586 chip_id_32 = bcm43xx_read32(bcm, 0);
2587 chip_id_16 = chip_id_32 & 0xFFFF;
Michael Buesche9357c02006-03-13 19:27:34 +01002588 bcm->core_chipcommon.available = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002589 bcm->core_chipcommon.id = core_id;
2590 bcm->core_chipcommon.rev = core_rev;
2591 bcm->core_chipcommon.index = 0;
2592 /* While we are at it, also read the capabilities. */
2593 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2594 } else {
2595 /* without a chipCommon, use a hard coded table. */
2596 pci_device = bcm->pci_dev->device;
2597 if (pci_device == 0x4301)
2598 chip_id_16 = 0x4301;
2599 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2600 chip_id_16 = 0x4307;
2601 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2602 chip_id_16 = 0x4402;
2603 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2604 chip_id_16 = 0x4610;
2605 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2606 chip_id_16 = 0x4710;
2607#ifdef CONFIG_BCM947XX
2608 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2609 chip_id_16 = 0x4309;
2610#endif
2611 else {
2612 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2613 return -ENODEV;
2614 }
2615 }
2616
2617 /* ChipCommon with Core Rev >=4 encodes number of cores,
2618 * otherwise consult hardcoded table */
2619 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2620 core_count = (chip_id_32 & 0x0F000000) >> 24;
2621 } else {
2622 switch (chip_id_16) {
2623 case 0x4610:
2624 case 0x4704:
2625 case 0x4710:
2626 core_count = 9;
2627 break;
2628 case 0x4310:
2629 core_count = 8;
2630 break;
2631 case 0x5365:
2632 core_count = 7;
2633 break;
2634 case 0x4306:
2635 core_count = 6;
2636 break;
2637 case 0x4301:
2638 case 0x4307:
2639 core_count = 5;
2640 break;
2641 case 0x4402:
2642 core_count = 3;
2643 break;
2644 default:
2645 /* SOL if we get here */
2646 assert(0);
2647 core_count = 1;
2648 }
2649 }
2650
2651 bcm->chip_id = chip_id_16;
Michael Bueschadc40e92006-03-25 20:36:57 +01002652 bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16;
2653 bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20;
John W. Linvillef2223132006-01-23 16:59:58 -05002654
2655 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2656 bcm->chip_id, bcm->chip_rev);
2657 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
Michael Buesche9357c02006-03-13 19:27:34 +01002658 if (bcm->core_chipcommon.available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002659 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2660 core_id, core_rev, core_vendor,
2661 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2662 }
2663
Michael Buesche9357c02006-03-13 19:27:34 +01002664 if (bcm->core_chipcommon.available)
John W. Linvillef2223132006-01-23 16:59:58 -05002665 current_core = 1;
2666 else
2667 current_core = 0;
2668 for ( ; current_core < core_count; current_core++) {
2669 struct bcm43xx_coreinfo *core;
Michael Buesche9357c02006-03-13 19:27:34 +01002670 struct bcm43xx_coreinfo_80211 *ext_80211;
John W. Linvillef2223132006-01-23 16:59:58 -05002671
2672 err = _switch_core(bcm, current_core);
2673 if (err)
2674 goto out;
2675 /* Gather information */
2676 /* fetch sb_id_hi from core information registers */
2677 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2678
2679 /* extract core_id, core_rev, core_vendor */
2680 core_id = (sb_id_hi & 0xFFF0) >> 4;
2681 core_rev = (sb_id_hi & 0xF);
2682 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2683
2684 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2685 current_core, core_id, core_rev, core_vendor,
2686 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2687
2688 core = NULL;
2689 switch (core_id) {
2690 case BCM43xx_COREID_PCI:
2691 core = &bcm->core_pci;
Michael Buesche9357c02006-03-13 19:27:34 +01002692 if (core->available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002693 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2694 continue;
2695 }
2696 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002697 case BCM43xx_COREID_80211:
2698 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2699 core = &(bcm->core_80211[i]);
Michael Buesche9357c02006-03-13 19:27:34 +01002700 ext_80211 = &(bcm->core_80211_ext[i]);
2701 if (!core->available)
John W. Linvillef2223132006-01-23 16:59:58 -05002702 break;
2703 core = NULL;
2704 }
2705 if (!core) {
2706 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2707 BCM43xx_MAX_80211_CORES);
2708 continue;
2709 }
2710 if (i != 0) {
2711 /* More than one 80211 core is only supported
2712 * by special chips.
2713 * There are chips with two 80211 cores, but with
2714 * dangling pins on the second core. Be careful
2715 * and ignore these cores here.
2716 */
2717 if (bcm->pci_dev->device != 0x4324) {
2718 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2719 continue;
2720 }
2721 }
2722 switch (core_rev) {
2723 case 2:
2724 case 4:
2725 case 5:
2726 case 6:
2727 case 7:
2728 case 9:
2729 break;
2730 default:
2731 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2732 core_rev);
2733 err = -ENODEV;
2734 goto out;
2735 }
Michael Buesche9357c02006-03-13 19:27:34 +01002736 bcm->nr_80211_available++;
2737 bcm43xx_init_struct_phyinfo(&ext_80211->phy);
2738 bcm43xx_init_struct_radioinfo(&ext_80211->radio);
John W. Linvillef2223132006-01-23 16:59:58 -05002739 break;
2740 case BCM43xx_COREID_CHIPCOMMON:
2741 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2742 break;
John W. Linvillef2223132006-01-23 16:59:58 -05002743 }
2744 if (core) {
Michael Buesche9357c02006-03-13 19:27:34 +01002745 core->available = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002746 core->id = core_id;
2747 core->rev = core_rev;
2748 core->index = current_core;
2749 }
2750 }
2751
Michael Buesche9357c02006-03-13 19:27:34 +01002752 if (!bcm->core_80211[0].available) {
John W. Linvillef2223132006-01-23 16:59:58 -05002753 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2754 err = -ENODEV;
2755 goto out;
2756 }
2757
2758 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2759
2760 assert(err == 0);
2761out:
2762 return err;
2763}
2764
2765static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2766{
2767 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2768 u8 *bssid = bcm->ieee->bssid;
2769
2770 switch (bcm->ieee->iw_mode) {
2771 case IW_MODE_ADHOC:
2772 random_ether_addr(bssid);
2773 break;
2774 case IW_MODE_MASTER:
2775 case IW_MODE_INFRA:
2776 case IW_MODE_REPEAT:
2777 case IW_MODE_SECOND:
2778 case IW_MODE_MONITOR:
2779 memcpy(bssid, mac, ETH_ALEN);
2780 break;
2781 default:
2782 assert(0);
2783 }
2784}
2785
2786static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
2787 u16 rate,
2788 int is_ofdm)
2789{
2790 u16 offset;
2791
2792 if (is_ofdm) {
2793 offset = 0x480;
2794 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2795 }
2796 else {
2797 offset = 0x4C0;
2798 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2799 }
2800 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
2801 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
2802}
2803
2804static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
2805{
Michael Buesche9357c02006-03-13 19:27:34 +01002806 switch (bcm43xx_current_phy(bcm)->type) {
John W. Linvillef2223132006-01-23 16:59:58 -05002807 case BCM43xx_PHYTYPE_A:
2808 case BCM43xx_PHYTYPE_G:
2809 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
2810 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
2811 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
2812 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
2813 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
2814 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
2815 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
2816 case BCM43xx_PHYTYPE_B:
2817 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
2818 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
2819 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
2820 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
2821 break;
2822 default:
2823 assert(0);
2824 }
2825}
2826
2827static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2828{
2829 bcm43xx_chip_cleanup(bcm);
2830 bcm43xx_pio_free(bcm);
2831 bcm43xx_dma_free(bcm);
2832
Michael Buesche9357c02006-03-13 19:27:34 +01002833 bcm->current_core->initialized = 0;
John W. Linvillef2223132006-01-23 16:59:58 -05002834}
2835
2836/* http://bcm-specs.sipsolutions.net/80211Init */
2837static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2838{
Michael Buesche9357c02006-03-13 19:27:34 +01002839 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2840 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05002841 u32 ucodeflags;
2842 int err;
2843 u32 sbimconfiglow;
2844 u8 limit;
2845
2846 if (bcm->chip_rev < 5) {
2847 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
2848 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
2849 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
2850 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
2851 sbimconfiglow |= 0x32;
2852 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
2853 sbimconfiglow |= 0x53;
2854 else
2855 assert(0);
2856 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
2857 }
2858
2859 bcm43xx_phy_calibrate(bcm);
2860 err = bcm43xx_chip_init(bcm);
2861 if (err)
2862 goto out;
2863
2864 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
2865 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
2866
2867 if (0 /*FIXME: which condition has to be used here? */)
2868 ucodeflags |= 0x00000010;
2869
2870 /* HW decryption needs to be set now */
2871 ucodeflags |= 0x40000000;
2872
Michael Buesche9357c02006-03-13 19:27:34 +01002873 if (phy->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -05002874 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
Michael Buesche9357c02006-03-13 19:27:34 +01002875 if (phy->rev == 1)
John W. Linvillef2223132006-01-23 16:59:58 -05002876 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
2877 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
2878 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
Michael Buesche9357c02006-03-13 19:27:34 +01002879 } else if (phy->type == BCM43xx_PHYTYPE_B) {
John W. Linvillef2223132006-01-23 16:59:58 -05002880 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
Michael Buesche9357c02006-03-13 19:27:34 +01002881 if (phy->rev >= 2 && radio->version == 0x2050)
John W. Linvillef2223132006-01-23 16:59:58 -05002882 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
2883 }
2884
2885 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2886 BCM43xx_UCODEFLAGS_OFFSET)) {
2887 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2888 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
2889 }
2890
2891 /* Short/Long Retry Limit.
2892 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
2893 * the chip-internal counter.
2894 */
2895 limit = limit_value(modparam_short_retry, 0, 0xF);
2896 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
2897 limit = limit_value(modparam_long_retry, 0, 0xF);
2898 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
2899
2900 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
2901 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
2902
2903 bcm43xx_rate_memory_init(bcm);
2904
2905 /* Minimum Contention Window */
Michael Buesche9357c02006-03-13 19:27:34 +01002906 if (phy->type == BCM43xx_PHYTYPE_B)
John W. Linvillef2223132006-01-23 16:59:58 -05002907 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
2908 else
2909 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
2910 /* Maximum Contention Window */
2911 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
2912
2913 bcm43xx_gen_bssid(bcm);
2914 bcm43xx_write_mac_bssid_templates(bcm);
2915
2916 if (bcm->current_core->rev >= 5)
2917 bcm43xx_write16(bcm, 0x043C, 0x000C);
2918
Michael Buesch77db31e2006-02-12 16:47:44 +01002919 if (bcm43xx_using_pio(bcm))
John W. Linvillef2223132006-01-23 16:59:58 -05002920 err = bcm43xx_pio_init(bcm);
Michael Buesch77db31e2006-02-12 16:47:44 +01002921 else
2922 err = bcm43xx_dma_init(bcm);
2923 if (err)
2924 goto err_chip_cleanup;
John W. Linvillef2223132006-01-23 16:59:58 -05002925 bcm43xx_write16(bcm, 0x0612, 0x0050);
2926 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2927 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2928
2929 bcm43xx_mac_enable(bcm);
2930 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2931
Michael Buesche9357c02006-03-13 19:27:34 +01002932 bcm->current_core->initialized = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05002933out:
2934 return err;
2935
2936err_chip_cleanup:
2937 bcm43xx_chip_cleanup(bcm);
2938 goto out;
2939}
2940
2941static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
2942{
2943 int err;
2944 u16 pci_status;
2945
2946 err = bcm43xx_pctl_set_crystal(bcm, 1);
2947 if (err)
2948 goto out;
2949 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
2950 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
2951
2952out:
2953 return err;
2954}
2955
2956static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
2957{
2958 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
2959 bcm43xx_pctl_set_crystal(bcm, 0);
2960}
2961
Michael Buesch489423c2006-02-13 00:11:07 +01002962static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
2963 u32 address,
2964 u32 data)
John W. Linvillef2223132006-01-23 16:59:58 -05002965{
2966 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
2967 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
2968}
2969
2970static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
2971{
2972 int err;
2973 struct bcm43xx_coreinfo *old_core;
2974
2975 old_core = bcm->current_core;
2976 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2977 if (err)
2978 goto out;
2979
2980 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
2981
2982 bcm43xx_switch_core(bcm, old_core);
2983 assert(err == 0);
2984out:
2985 return err;
2986}
2987
2988/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
2989 * To enable core 0, pass a core_mask of 1<<0
2990 */
2991static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
2992 u32 core_mask)
2993{
2994 u32 backplane_flag_nr;
2995 u32 value;
2996 struct bcm43xx_coreinfo *old_core;
2997 int err = 0;
2998
2999 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
3000 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
3001
3002 old_core = bcm->current_core;
3003 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
3004 if (err)
3005 goto out;
3006
3007 if (bcm->core_pci.rev < 6) {
3008 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
3009 value |= (1 << backplane_flag_nr);
3010 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
3011 } else {
3012 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
3013 if (err) {
3014 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3015 goto out_switch_back;
3016 }
3017 value |= core_mask << 8;
3018 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3019 if (err) {
3020 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3021 goto out_switch_back;
3022 }
3023 }
3024
3025 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3026 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3027 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3028
3029 if (bcm->core_pci.rev < 5) {
3030 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3031 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3032 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3033 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3034 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3035 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3036 err = bcm43xx_pcicore_commit_settings(bcm);
3037 assert(err == 0);
3038 }
3039
3040out_switch_back:
3041 err = bcm43xx_switch_core(bcm, old_core);
3042out:
3043 return err;
3044}
3045
3046static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3047{
3048 ieee80211softmac_start(bcm->net_dev);
3049}
3050
Michael Bueschab4977f2006-02-12 22:40:39 +01003051static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003052{
Michael Buesche9357c02006-03-13 19:27:34 +01003053 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003054
Michael Bueschab4977f2006-02-12 22:40:39 +01003055 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3056 return;
John W. Linvillef2223132006-01-23 16:59:58 -05003057
Michael Bueschab4977f2006-02-12 22:40:39 +01003058 bcm43xx_mac_suspend(bcm);
3059 bcm43xx_phy_lo_g_measure(bcm);
3060 bcm43xx_mac_enable(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003061}
3062
Michael Bueschab4977f2006-02-12 22:40:39 +01003063static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003064{
John W. Linvillef2223132006-01-23 16:59:58 -05003065 bcm43xx_phy_lo_mark_all_unused(bcm);
3066 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3067 bcm43xx_mac_suspend(bcm);
3068 bcm43xx_calc_nrssi_slope(bcm);
3069 bcm43xx_mac_enable(bcm);
3070 }
John W. Linvillef2223132006-01-23 16:59:58 -05003071}
3072
Michael Bueschab4977f2006-02-12 22:40:39 +01003073static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
John W. Linvillef2223132006-01-23 16:59:58 -05003074{
John W. Linvillef2223132006-01-23 16:59:58 -05003075 /* Update device statistics. */
3076 bcm43xx_calculate_link_quality(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003077}
John W. Linvillef2223132006-01-23 16:59:58 -05003078
Michael Bueschab4977f2006-02-12 22:40:39 +01003079static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3080{
Michael Buesche9357c02006-03-13 19:27:34 +01003081 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
3082 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003083
3084 if (phy->type == BCM43xx_PHYTYPE_G) {
3085 //TODO: update_aci_moving_average
3086 if (radio->aci_enable && radio->aci_wlan_automatic) {
3087 bcm43xx_mac_suspend(bcm);
3088 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3089 if (0 /*TODO: bunch of conditions*/) {
3090 bcm43xx_radio_set_interference_mitigation(bcm,
3091 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3092 }
3093 } else if (1/*TODO*/) {
3094 /*
3095 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3096 bcm43xx_radio_set_interference_mitigation(bcm,
3097 BCM43xx_RADIO_INTERFMODE_NONE);
3098 }
3099 */
3100 }
3101 bcm43xx_mac_enable(bcm);
3102 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3103 phy->rev == 1) {
3104 //TODO: implement rev1 workaround
3105 }
John W. Linvillef2223132006-01-23 16:59:58 -05003106 }
Michael Bueschab4977f2006-02-12 22:40:39 +01003107 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3108 //TODO for APHY (temperature?)
3109}
3110
Michael Buesch78ff56a2006-06-05 20:24:10 +02003111static void bcm43xx_periodic_work_handler(void *d)
Michael Bueschab4977f2006-02-12 22:40:39 +01003112{
Michael Buesch78ff56a2006-06-05 20:24:10 +02003113 struct bcm43xx_private *bcm = d;
Michael Bueschab4977f2006-02-12 22:40:39 +01003114 unsigned long flags;
3115 unsigned int state;
3116
Michael Buesch78ff56a2006-06-05 20:24:10 +02003117 bcm43xx_lock_irqsafe(bcm, flags);
Michael Bueschab4977f2006-02-12 22:40:39 +01003118
Michael Bueschab4977f2006-02-12 22:40:39 +01003119 state = bcm->periodic_state;
3120 if (state % 8 == 0)
3121 bcm43xx_periodic_every120sec(bcm);
3122 if (state % 4 == 0)
3123 bcm43xx_periodic_every60sec(bcm);
3124 if (state % 2 == 0)
3125 bcm43xx_periodic_every30sec(bcm);
3126 bcm43xx_periodic_every15sec(bcm);
3127 bcm->periodic_state = state + 1;
3128
Michael Buesch78ff56a2006-06-05 20:24:10 +02003129 schedule_delayed_work(&bcm->periodic_work, HZ * 15);
Michael Bueschab4977f2006-02-12 22:40:39 +01003130
Michael Buesch78ff56a2006-06-05 20:24:10 +02003131 mmiowb();
3132 bcm43xx_unlock_irqsafe(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003133}
3134
John W. Linvillef2223132006-01-23 16:59:58 -05003135static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3136{
Michael Buesch78ff56a2006-06-05 20:24:10 +02003137 cancel_rearming_delayed_work(&bcm->periodic_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003138}
3139
John W. Linvillef2223132006-01-23 16:59:58 -05003140static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3141{
Michael Buesch78ff56a2006-06-05 20:24:10 +02003142 struct work_struct *work = &(bcm->periodic_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003143
Michael Buesch78ff56a2006-06-05 20:24:10 +02003144 assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
3145 INIT_WORK(work, bcm43xx_periodic_work_handler, bcm);
3146 schedule_work(work);
John W. Linvillef2223132006-01-23 16:59:58 -05003147}
3148
3149static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3150{
3151 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3152 0x0056) * 2;
3153 bcm43xx_clear_keys(bcm);
3154}
3155
3156/* This is the opposite of bcm43xx_init_board() */
3157static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3158{
3159 int i, err;
John W. Linvillef2223132006-01-23 16:59:58 -05003160
Michael Buesch78ff56a2006-06-05 20:24:10 +02003161 bcm43xx_lock_noirq(bcm);
Michael Buesch367f8992006-02-28 15:32:19 +01003162 bcm43xx_sysfs_unregister(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003163 bcm43xx_periodic_tasks_delete(bcm);
3164
Michael Buesch78ff56a2006-06-05 20:24:10 +02003165 bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
John W. Linvillef2223132006-01-23 16:59:58 -05003166
John W. Linvillef2223132006-01-23 16:59:58 -05003167 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003168 if (!bcm->core_80211[i].available)
John W. Linvillef2223132006-01-23 16:59:58 -05003169 continue;
Michael Buesche9357c02006-03-13 19:27:34 +01003170 if (!bcm->core_80211[i].initialized)
John W. Linvillef2223132006-01-23 16:59:58 -05003171 continue;
3172
3173 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3174 assert(err == 0);
3175 bcm43xx_wireless_core_cleanup(bcm);
3176 }
3177
3178 bcm43xx_pctl_set_crystal(bcm, 0);
3179
Michael Buesch78ff56a2006-06-05 20:24:10 +02003180 bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
3181 bcm43xx_unlock_noirq(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003182}
3183
3184static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3185{
3186 int i, err;
John W. Linvillef2223132006-01-23 16:59:58 -05003187 int connect_phy;
John W. Linvillef2223132006-01-23 16:59:58 -05003188
3189 might_sleep();
3190
Michael Buesch78ff56a2006-06-05 20:24:10 +02003191 bcm43xx_lock_noirq(bcm);
3192 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
John W. Linvillef2223132006-01-23 16:59:58 -05003193
3194 err = bcm43xx_pctl_set_crystal(bcm, 1);
3195 if (err)
3196 goto out;
3197 err = bcm43xx_pctl_init(bcm);
3198 if (err)
3199 goto err_crystal_off;
3200 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3201 if (err)
3202 goto err_crystal_off;
3203
3204 tasklet_enable(&bcm->isr_tasklet);
Michael Buesche9357c02006-03-13 19:27:34 +01003205 for (i = 0; i < bcm->nr_80211_available; i++) {
John W. Linvillef2223132006-01-23 16:59:58 -05003206 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3207 assert(err != -ENODEV);
3208 if (err)
3209 goto err_80211_unwind;
3210
3211 /* Enable the selected wireless core.
3212 * Connect PHY only on the first core.
3213 */
3214 if (!bcm43xx_core_enabled(bcm)) {
Michael Buesche9357c02006-03-13 19:27:34 +01003215 if (bcm->nr_80211_available == 1) {
3216 connect_phy = bcm43xx_current_phy(bcm)->connected;
John W. Linvillef2223132006-01-23 16:59:58 -05003217 } else {
3218 if (i == 0)
3219 connect_phy = 1;
3220 else
3221 connect_phy = 0;
3222 }
3223 bcm43xx_wireless_core_reset(bcm, connect_phy);
3224 }
3225
3226 if (i != 0)
3227 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3228
3229 err = bcm43xx_wireless_core_init(bcm);
3230 if (err)
3231 goto err_80211_unwind;
3232
3233 if (i != 0) {
3234 bcm43xx_mac_suspend(bcm);
3235 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3236 bcm43xx_radio_turn_off(bcm);
3237 }
3238 }
3239 bcm->active_80211_core = &bcm->core_80211[0];
Michael Buesche9357c02006-03-13 19:27:34 +01003240 if (bcm->nr_80211_available >= 2) {
John W. Linvillef2223132006-01-23 16:59:58 -05003241 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3242 bcm43xx_mac_enable(bcm);
3243 }
3244 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3245 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3246 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3247 bcm43xx_security_init(bcm);
3248 bcm43xx_softmac_init(bcm);
3249
3250 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3251
Michael Buesche9357c02006-03-13 19:27:34 +01003252 if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
John W. Linvillef2223132006-01-23 16:59:58 -05003253 bcm43xx_mac_suspend(bcm);
Michael Buesche9357c02006-03-13 19:27:34 +01003254 bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
John W. Linvillef2223132006-01-23 16:59:58 -05003255 bcm43xx_mac_enable(bcm);
3256 }
Michael Bueschcad2b312006-02-21 18:08:55 +01003257
3258 /* Initialization of the board is done. Flag it as such. */
Michael Buesch78ff56a2006-06-05 20:24:10 +02003259 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
Michael Bueschcad2b312006-02-21 18:08:55 +01003260
John W. Linvillef2223132006-01-23 16:59:58 -05003261 bcm43xx_periodic_tasks_setup(bcm);
Michael Buesch367f8992006-02-28 15:32:19 +01003262 bcm43xx_sysfs_register(bcm);
3263 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
John W. Linvillef2223132006-01-23 16:59:58 -05003264
David Woodhousebc519f32006-05-05 17:38:27 +01003265 /*FIXME: This should be handled by softmac instead. */
3266 schedule_work(&bcm->softmac->associnfo.work);
3267
John W. Linvillef2223132006-01-23 16:59:58 -05003268 assert(err == 0);
3269out:
Michael Buesch78ff56a2006-06-05 20:24:10 +02003270 bcm43xx_unlock_noirq(bcm);
3271
John W. Linvillef2223132006-01-23 16:59:58 -05003272 return err;
3273
3274err_80211_unwind:
3275 tasklet_disable(&bcm->isr_tasklet);
3276 /* unwind all 80211 initialization */
Michael Buesche9357c02006-03-13 19:27:34 +01003277 for (i = 0; i < bcm->nr_80211_available; i++) {
3278 if (!bcm->core_80211[i].initialized)
John W. Linvillef2223132006-01-23 16:59:58 -05003279 continue;
3280 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3281 bcm43xx_wireless_core_cleanup(bcm);
3282 }
3283err_crystal_off:
3284 bcm43xx_pctl_set_crystal(bcm, 0);
3285 goto out;
3286}
3287
3288static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3289{
3290 struct pci_dev *pci_dev = bcm->pci_dev;
3291 int i;
3292
3293 bcm43xx_chipset_detach(bcm);
3294 /* Do _not_ access the chip, after it is detached. */
Michael Bueschcc935712006-04-10 02:08:33 +02003295 pci_iounmap(pci_dev, bcm->mmio_addr);
John W. Linvillef2223132006-01-23 16:59:58 -05003296 pci_release_regions(pci_dev);
3297 pci_disable_device(pci_dev);
3298
3299 /* Free allocated structures/fields */
3300 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003301 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3302 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3303 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
John W. Linvillef2223132006-01-23 16:59:58 -05003304 }
3305}
3306
3307static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3308{
Michael Buesche9357c02006-03-13 19:27:34 +01003309 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003310 u16 value;
3311 u8 phy_version;
3312 u8 phy_type;
3313 u8 phy_rev;
3314 int phy_rev_ok = 1;
3315 void *p;
3316
3317 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3318
3319 phy_version = (value & 0xF000) >> 12;
3320 phy_type = (value & 0x0F00) >> 8;
3321 phy_rev = (value & 0x000F);
3322
3323 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3324 phy_version, phy_type, phy_rev);
3325
3326 switch (phy_type) {
3327 case BCM43xx_PHYTYPE_A:
3328 if (phy_rev >= 4)
3329 phy_rev_ok = 0;
3330 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3331 * if we switch 80211 cores after init is done.
3332 * As we do not implement on the fly switching between
3333 * wireless cores, I will leave this as a future task.
3334 */
3335 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3336 bcm->ieee->mode = IEEE_A;
3337 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3338 IEEE80211_24GHZ_BAND;
3339 break;
3340 case BCM43xx_PHYTYPE_B:
3341 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3342 phy_rev_ok = 0;
3343 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3344 bcm->ieee->mode = IEEE_B;
3345 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3346 break;
3347 case BCM43xx_PHYTYPE_G:
3348 if (phy_rev > 7)
3349 phy_rev_ok = 0;
3350 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3351 IEEE80211_CCK_MODULATION;
3352 bcm->ieee->mode = IEEE_G;
3353 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3354 break;
3355 default:
3356 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3357 phy_type);
3358 return -ENODEV;
3359 };
3360 if (!phy_rev_ok) {
3361 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3362 phy_rev);
3363 }
3364
Michael Buesch489423c2006-02-13 00:11:07 +01003365 phy->version = phy_version;
3366 phy->type = phy_type;
3367 phy->rev = phy_rev;
John W. Linvillef2223132006-01-23 16:59:58 -05003368 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3369 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3370 GFP_KERNEL);
3371 if (!p)
3372 return -ENOMEM;
Michael Buesch489423c2006-02-13 00:11:07 +01003373 phy->_lo_pairs = p;
John W. Linvillef2223132006-01-23 16:59:58 -05003374 }
3375
3376 return 0;
3377}
3378
3379static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3380{
3381 struct pci_dev *pci_dev = bcm->pci_dev;
3382 struct net_device *net_dev = bcm->net_dev;
3383 int err;
3384 int i;
John W. Linvillef2223132006-01-23 16:59:58 -05003385 u32 coremask;
3386
3387 err = pci_enable_device(pci_dev);
3388 if (err) {
Michael Bueschcc935712006-04-10 02:08:33 +02003389 printk(KERN_ERR PFX "pci_enable_device() failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05003390 goto out;
3391 }
Michael Buesch65f3f192006-01-31 20:11:38 +01003392 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
John W. Linvillef2223132006-01-23 16:59:58 -05003393 if (err) {
Michael Bueschcc935712006-04-10 02:08:33 +02003394 printk(KERN_ERR PFX "pci_request_regions() failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05003395 goto err_pci_disable;
3396 }
John W. Linvillef2223132006-01-23 16:59:58 -05003397 /* enable PCI bus-mastering */
3398 pci_set_master(pci_dev);
Michael Bueschcc935712006-04-10 02:08:33 +02003399 bcm->mmio_addr = pci_iomap(pci_dev, 0, ~0UL);
Michael Buesch4a1821e2006-03-18 20:19:12 +01003400 if (!bcm->mmio_addr) {
Michael Bueschcc935712006-04-10 02:08:33 +02003401 printk(KERN_ERR PFX "pci_iomap() failed\n");
John W. Linvillef2223132006-01-23 16:59:58 -05003402 err = -EIO;
3403 goto err_pci_release;
3404 }
Michael Buesch4a1821e2006-03-18 20:19:12 +01003405 net_dev->base_addr = (unsigned long)bcm->mmio_addr;
John W. Linvillef2223132006-01-23 16:59:58 -05003406
3407 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3408 &bcm->board_vendor);
3409 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3410 &bcm->board_type);
3411 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3412 &bcm->board_revision);
3413
3414 err = bcm43xx_chipset_attach(bcm);
3415 if (err)
3416 goto err_iounmap;
3417 err = bcm43xx_pctl_init(bcm);
3418 if (err)
3419 goto err_chipset_detach;
3420 err = bcm43xx_probe_cores(bcm);
3421 if (err)
3422 goto err_chipset_detach;
3423
John W. Linvillef2223132006-01-23 16:59:58 -05003424 /* Attach all IO cores to the backplane. */
3425 coremask = 0;
Michael Buesche9357c02006-03-13 19:27:34 +01003426 for (i = 0; i < bcm->nr_80211_available; i++)
John W. Linvillef2223132006-01-23 16:59:58 -05003427 coremask |= (1 << bcm->core_80211[i].index);
3428 //FIXME: Also attach some non80211 cores?
3429 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3430 if (err) {
3431 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3432 goto err_chipset_detach;
3433 }
3434
Michael Bueschea0922b2006-02-19 14:09:20 +01003435 err = bcm43xx_sprom_extract(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003436 if (err)
3437 goto err_chipset_detach;
3438 err = bcm43xx_leds_init(bcm);
3439 if (err)
3440 goto err_chipset_detach;
3441
Michael Buesche9357c02006-03-13 19:27:34 +01003442 for (i = 0; i < bcm->nr_80211_available; i++) {
John W. Linvillef2223132006-01-23 16:59:58 -05003443 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3444 assert(err != -ENODEV);
3445 if (err)
3446 goto err_80211_unwind;
3447
3448 /* Enable the selected wireless core.
3449 * Connect PHY only on the first core.
3450 */
3451 bcm43xx_wireless_core_reset(bcm, (i == 0));
3452
3453 err = bcm43xx_read_phyinfo(bcm);
3454 if (err && (i == 0))
3455 goto err_80211_unwind;
3456
3457 err = bcm43xx_read_radioinfo(bcm);
3458 if (err && (i == 0))
3459 goto err_80211_unwind;
3460
3461 err = bcm43xx_validate_chip(bcm);
3462 if (err && (i == 0))
3463 goto err_80211_unwind;
3464
3465 bcm43xx_radio_turn_off(bcm);
3466 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3467 if (err)
3468 goto err_80211_unwind;
3469 bcm43xx_wireless_core_disable(bcm);
3470 }
Michael Buesch869aaab2006-05-05 17:23:51 +02003471 err = bcm43xx_geo_init(bcm);
3472 if (err)
3473 goto err_80211_unwind;
John W. Linvillef2223132006-01-23 16:59:58 -05003474 bcm43xx_pctl_set_crystal(bcm, 0);
3475
3476 /* Set the MAC address in the networking subsystem */
Stefano Briviof9f7b962006-05-05 01:26:29 +02003477 if (is_valid_ether_addr(bcm->sprom.et1macaddr))
John W. Linvillef2223132006-01-23 16:59:58 -05003478 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3479 else
3480 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3481
John W. Linvillef2223132006-01-23 16:59:58 -05003482 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3483 "Broadcom %04X", bcm->chip_id);
3484
3485 assert(err == 0);
3486out:
3487 return err;
3488
3489err_80211_unwind:
3490 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
Michael Buesche9357c02006-03-13 19:27:34 +01003491 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3492 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3493 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
John W. Linvillef2223132006-01-23 16:59:58 -05003494 }
3495err_chipset_detach:
3496 bcm43xx_chipset_detach(bcm);
3497err_iounmap:
Michael Bueschcc935712006-04-10 02:08:33 +02003498 pci_iounmap(pci_dev, bcm->mmio_addr);
John W. Linvillef2223132006-01-23 16:59:58 -05003499err_pci_release:
3500 pci_release_regions(pci_dev);
3501err_pci_disable:
3502 pci_disable_device(pci_dev);
3503 goto out;
3504}
3505
John W. Linvillef2223132006-01-23 16:59:58 -05003506/* Do the Hardware IO operations to send the txb */
3507static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3508 struct ieee80211_txb *txb)
3509{
3510 int err = -ENODEV;
3511
Michael Buesch77db31e2006-02-12 16:47:44 +01003512 if (bcm43xx_using_pio(bcm))
3513 err = bcm43xx_pio_tx(bcm, txb);
John W. Linvillef2223132006-01-23 16:59:58 -05003514 else
Michael Bueschea72ab22006-01-27 17:26:20 +01003515 err = bcm43xx_dma_tx(bcm, txb);
Michael Bueschb79367a2006-04-10 02:39:54 +02003516 bcm->net_dev->trans_start = jiffies;
John W. Linvillef2223132006-01-23 16:59:58 -05003517
3518 return err;
3519}
3520
3521static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3522 u8 channel)
3523{
3524 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschec483782006-03-27 11:49:51 +02003525 struct bcm43xx_radioinfo *radio;
John W. Linvillef2223132006-01-23 16:59:58 -05003526 unsigned long flags;
3527
Michael Buesch78ff56a2006-06-05 20:24:10 +02003528 bcm43xx_lock_irqsafe(bcm, flags);
3529 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
Michael Bueschec483782006-03-27 11:49:51 +02003530 bcm43xx_mac_suspend(bcm);
3531 bcm43xx_radio_selectchannel(bcm, channel, 0);
3532 bcm43xx_mac_enable(bcm);
3533 } else {
3534 radio = bcm43xx_current_radio(bcm);
3535 radio->initial_channel = channel;
3536 }
Michael Buesch78ff56a2006-06-05 20:24:10 +02003537 bcm43xx_unlock_irqsafe(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
Jason Lunzff7562a2006-06-04 23:05:49 +02003549 dprintk(KERN_INFO PFX "set security called");
Michael Bueschefccb642006-03-11 13:39:14 +01003550
Michael Buesch78ff56a2006-06-05 20:24:10 +02003551 bcm43xx_lock_irqsafe(bcm, flags);
Michael Bueschefccb642006-03-11 13:39:14 +01003552
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;
Jason Lunzff7562a2006-06-04 23:05:49 +02003562 dprintk(", .active_key = %d", sec->active_key);
John W. Linvillef2223132006-01-23 16:59:58 -05003563 }
3564 if (sec->flags & SEC_UNICAST_GROUP) {
3565 secinfo->unicast_uses_group = sec->unicast_uses_group;
Jason Lunzff7562a2006-06-04 23:05:49 +02003566 dprintk(", .unicast_uses_group = %d", sec->unicast_uses_group);
John W. Linvillef2223132006-01-23 16:59:58 -05003567 }
3568 if (sec->flags & SEC_LEVEL) {
3569 secinfo->level = sec->level;
Jason Lunzff7562a2006-06-04 23:05:49 +02003570 dprintk(", .level = %d", sec->level);
John W. Linvillef2223132006-01-23 16:59:58 -05003571 }
3572 if (sec->flags & SEC_ENABLED) {
3573 secinfo->enabled = sec->enabled;
Jason Lunzff7562a2006-06-04 23:05:49 +02003574 dprintk(", .enabled = %d", sec->enabled);
John W. Linvillef2223132006-01-23 16:59:58 -05003575 }
3576 if (sec->flags & SEC_ENCRYPT) {
3577 secinfo->encrypt = sec->encrypt;
Jason Lunzff7562a2006-06-04 23:05:49 +02003578 dprintk(", .encrypt = %d", sec->encrypt);
John W. Linvillef2223132006-01-23 16:59:58 -05003579 }
Jason Lunzff7562a2006-06-04 23:05:49 +02003580 dprintk("\n");
Michael Buesch78ff56a2006-06-05 20:24:10 +02003581 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
3582 !bcm->ieee->host_encrypt) {
John W. Linvillef2223132006-01-23 16:59:58 -05003583 if (secinfo->enabled) {
3584 /* upload WEP keys to hardware */
3585 char null_address[6] = { 0 };
3586 u8 algorithm = 0;
3587 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
3588 if (!(sec->flags & (1<<keyidx)))
3589 continue;
3590 switch (sec->encode_alg[keyidx]) {
3591 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
3592 case SEC_ALG_WEP:
3593 algorithm = BCM43xx_SEC_ALGO_WEP;
3594 if (secinfo->key_sizes[keyidx] == 13)
3595 algorithm = BCM43xx_SEC_ALGO_WEP104;
3596 break;
3597 case SEC_ALG_TKIP:
3598 FIXME();
3599 algorithm = BCM43xx_SEC_ALGO_TKIP;
3600 break;
3601 case SEC_ALG_CCMP:
3602 FIXME();
3603 algorithm = BCM43xx_SEC_ALGO_AES;
3604 break;
3605 default:
3606 assert(0);
3607 break;
3608 }
3609 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
3610 bcm->key[keyidx].enabled = 1;
3611 bcm->key[keyidx].algorithm = algorithm;
3612 }
3613 } else
3614 bcm43xx_clear_keys(bcm);
3615 }
Michael Buesch78ff56a2006-06-05 20:24:10 +02003616 bcm43xx_unlock_irqsafe(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003617}
3618
3619/* hard_start_xmit() callback in struct ieee80211_device */
3620static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
3621 struct net_device *net_dev,
3622 int pri)
3623{
3624 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3625 int err = -ENODEV;
3626 unsigned long flags;
3627
Michael Buesch78ff56a2006-06-05 20:24:10 +02003628 bcm43xx_lock_irqonly(bcm, flags);
3629 if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
John W. Linvillef2223132006-01-23 16:59:58 -05003630 err = bcm43xx_tx(bcm, txb);
Michael Buesch78ff56a2006-06-05 20:24:10 +02003631 bcm43xx_unlock_irqonly(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003632
3633 return err;
3634}
3635
3636static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
3637{
3638 return &(bcm43xx_priv(net_dev)->ieee->stats);
3639}
3640
3641static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
3642{
3643 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschefccb642006-03-11 13:39:14 +01003644 unsigned long flags;
John W. Linvillef2223132006-01-23 16:59:58 -05003645
Michael Buesch78ff56a2006-06-05 20:24:10 +02003646 bcm43xx_lock_irqonly(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003647 bcm43xx_controller_restart(bcm, "TX timeout");
Michael Buesch78ff56a2006-06-05 20:24:10 +02003648 bcm43xx_unlock_irqonly(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003649}
3650
3651#ifdef CONFIG_NET_POLL_CONTROLLER
3652static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3653{
3654 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3655 unsigned long flags;
3656
3657 local_irq_save(flags);
3658 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3659 local_irq_restore(flags);
3660}
3661#endif /* CONFIG_NET_POLL_CONTROLLER */
3662
3663static int bcm43xx_net_open(struct net_device *net_dev)
3664{
3665 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3666
3667 return bcm43xx_init_board(bcm);
3668}
3669
3670static int bcm43xx_net_stop(struct net_device *net_dev)
3671{
3672 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3673
3674 ieee80211softmac_stop(net_dev);
3675 bcm43xx_disable_interrupts_sync(bcm, NULL);
3676 bcm43xx_free_board(bcm);
3677
3678 return 0;
3679}
3680
Michael Buesch77db31e2006-02-12 16:47:44 +01003681static int bcm43xx_init_private(struct bcm43xx_private *bcm,
3682 struct net_device *net_dev,
Michael Bueschab4977f2006-02-12 22:40:39 +01003683 struct pci_dev *pci_dev)
John W. Linvillef2223132006-01-23 16:59:58 -05003684{
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003685 int err;
3686
Michael Buesch78ff56a2006-06-05 20:24:10 +02003687 bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
John W. Linvillef2223132006-01-23 16:59:58 -05003688 bcm->ieee = netdev_priv(net_dev);
3689 bcm->softmac = ieee80211_priv(net_dev);
3690 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
John W. Linvillef2223132006-01-23 16:59:58 -05003691
John W. Linvillef2223132006-01-23 16:59:58 -05003692 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3693 bcm->pci_dev = pci_dev;
3694 bcm->net_dev = net_dev;
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003695 bcm->bad_frames_preempt = modparam_bad_frames_preempt;
Michael Buesch78ff56a2006-06-05 20:24:10 +02003696 spin_lock_init(&bcm->irq_lock);
3697 mutex_init(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -05003698 tasklet_init(&bcm->isr_tasklet,
3699 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
3700 (unsigned long)bcm);
3701 tasklet_disable_nosync(&bcm->isr_tasklet);
3702 if (modparam_pio) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003703 bcm->__using_pio = 1;
John W. Linvillef2223132006-01-23 16:59:58 -05003704 } else {
Michael Buesch4d5a9e0e2006-03-11 13:15:02 +01003705 err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
3706 err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
3707 if (err) {
Michael Buesch77db31e2006-02-12 16:47:44 +01003708#ifdef CONFIG_BCM43XX_PIO
John W. Linvillef2223132006-01-23 16:59:58 -05003709 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
Michael Buesch77db31e2006-02-12 16:47:44 +01003710 bcm->__using_pio = 1;
3711#else
3712 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
3713 "Recompile the driver with PIO support, please.\n");
3714 return -ENODEV;
3715#endif /* CONFIG_BCM43XX_PIO */
John W. Linvillef2223132006-01-23 16:59:58 -05003716 }
3717 }
3718 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
3719
3720 /* default to sw encryption for now */
3721 bcm->ieee->host_build_iv = 0;
3722 bcm->ieee->host_encrypt = 1;
3723 bcm->ieee->host_decrypt = 1;
3724
3725 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
3726 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
3727 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
3728 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
Michael Buesch77db31e2006-02-12 16:47:44 +01003729
3730 return 0;
John W. Linvillef2223132006-01-23 16:59:58 -05003731}
3732
3733static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
3734 const struct pci_device_id *ent)
3735{
3736 struct net_device *net_dev;
3737 struct bcm43xx_private *bcm;
John W. Linvillef2223132006-01-23 16:59:58 -05003738 int err;
3739
3740#ifdef CONFIG_BCM947XX
3741 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
3742 return -ENODEV;
3743#endif
3744
3745#ifdef DEBUG_SINGLE_DEVICE_ONLY
3746 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
3747 return -ENODEV;
3748#endif
3749
3750 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
3751 if (!net_dev) {
3752 printk(KERN_ERR PFX
3753 "could not allocate ieee80211 device %s\n",
3754 pci_name(pdev));
3755 err = -ENOMEM;
3756 goto out;
3757 }
3758 /* initialize the net_device struct */
3759 SET_MODULE_OWNER(net_dev);
3760 SET_NETDEV_DEV(net_dev, &pdev->dev);
3761
3762 net_dev->open = bcm43xx_net_open;
3763 net_dev->stop = bcm43xx_net_stop;
3764 net_dev->get_stats = bcm43xx_net_get_stats;
3765 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
3766#ifdef CONFIG_NET_POLL_CONTROLLER
3767 net_dev->poll_controller = bcm43xx_net_poll_controller;
3768#endif
3769 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
3770 net_dev->irq = pdev->irq;
Michael Buesch6465ce12006-02-02 19:11:08 +01003771 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
John W. Linvillef2223132006-01-23 16:59:58 -05003772
3773 /* initialize the bcm43xx_private struct */
3774 bcm = bcm43xx_priv(net_dev);
3775 memset(bcm, 0, sizeof(*bcm));
Michael Bueschab4977f2006-02-12 22:40:39 +01003776 err = bcm43xx_init_private(bcm, net_dev, pdev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003777 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003778 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003779
3780 pci_set_drvdata(pdev, net_dev);
3781
3782 err = bcm43xx_attach_board(bcm);
3783 if (err)
Michael Bueschab4977f2006-02-12 22:40:39 +01003784 goto err_free_netdev;
John W. Linvillef2223132006-01-23 16:59:58 -05003785
3786 err = register_netdev(net_dev);
3787 if (err) {
3788 printk(KERN_ERR PFX "Cannot register net device, "
3789 "aborting.\n");
3790 err = -ENOMEM;
3791 goto err_detach_board;
3792 }
3793
3794 bcm43xx_debugfs_add_device(bcm);
3795
3796 assert(err == 0);
3797out:
3798 return err;
3799
3800err_detach_board:
3801 bcm43xx_detach_board(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -05003802err_free_netdev:
3803 free_ieee80211softmac(net_dev);
3804 goto out;
3805}
3806
3807static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3808{
3809 struct net_device *net_dev = pci_get_drvdata(pdev);
3810 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3811
3812 bcm43xx_debugfs_remove_device(bcm);
3813 unregister_netdev(net_dev);
3814 bcm43xx_detach_board(bcm);
3815 assert(bcm->ucode == NULL);
John W. Linvillef2223132006-01-23 16:59:58 -05003816 free_ieee80211softmac(net_dev);
3817}
3818
3819/* Hard-reset the chip. Do not call this directly.
3820 * Use bcm43xx_controller_restart()
3821 */
3822static void bcm43xx_chip_reset(void *_bcm)
3823{
3824 struct bcm43xx_private *bcm = _bcm;
3825 struct net_device *net_dev = bcm->net_dev;
3826 struct pci_dev *pci_dev = bcm->pci_dev;
John W. Linvillef2223132006-01-23 16:59:58 -05003827 int err;
Michael Buesch78ff56a2006-06-05 20:24:10 +02003828 int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
John W. Linvillef2223132006-01-23 16:59:58 -05003829
3830 netif_stop_queue(bcm->net_dev);
3831 tasklet_disable(&bcm->isr_tasklet);
3832
3833 bcm->firmware_norelease = 1;
3834 if (was_initialized)
3835 bcm43xx_free_board(bcm);
3836 bcm->firmware_norelease = 0;
3837 bcm43xx_detach_board(bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003838 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
Michael Buesch77db31e2006-02-12 16:47:44 +01003839 if (err)
3840 goto failure;
John W. Linvillef2223132006-01-23 16:59:58 -05003841 err = bcm43xx_attach_board(bcm);
3842 if (err)
3843 goto failure;
3844 if (was_initialized) {
3845 err = bcm43xx_init_board(bcm);
3846 if (err)
3847 goto failure;
3848 }
3849 netif_wake_queue(bcm->net_dev);
3850 printk(KERN_INFO PFX "Controller restarted\n");
3851
3852 return;
3853failure:
3854 printk(KERN_ERR PFX "Controller restart failed\n");
3855}
3856
3857/* Hard-reset the chip.
3858 * This can be called from interrupt or process context.
3859 * Make sure to _not_ re-enable device interrupts after this has been called.
3860*/
3861void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
3862{
Michael Buesch78ff56a2006-06-05 20:24:10 +02003863 bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
John W. Linvillef2223132006-01-23 16:59:58 -05003864 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
Michael Buesch73733842006-03-12 19:44:29 +01003865 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
John W. Linvillef2223132006-01-23 16:59:58 -05003866 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
3867 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
Michael Bueschab4977f2006-02-12 22:40:39 +01003868 schedule_work(&bcm->restart_work);
John W. Linvillef2223132006-01-23 16:59:58 -05003869}
3870
3871#ifdef CONFIG_PM
3872
3873static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
3874{
3875 struct net_device *net_dev = pci_get_drvdata(pdev);
3876 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3877 unsigned long flags;
3878 int try_to_shutdown = 0, err;
3879
3880 dprintk(KERN_INFO PFX "Suspending...\n");
3881
Michael Buesch78ff56a2006-06-05 20:24:10 +02003882 bcm43xx_lock_irqsafe(bcm, flags);
3883 bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
3884 if (bcm->was_initialized)
John W. Linvillef2223132006-01-23 16:59:58 -05003885 try_to_shutdown = 1;
Michael Buesch78ff56a2006-06-05 20:24:10 +02003886 bcm43xx_unlock_irqsafe(bcm, flags);
John W. Linvillef2223132006-01-23 16:59:58 -05003887
3888 netif_device_detach(net_dev);
3889 if (try_to_shutdown) {
3890 ieee80211softmac_stop(net_dev);
3891 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
3892 if (unlikely(err)) {
3893 dprintk(KERN_ERR PFX "Suspend failed.\n");
3894 return -EAGAIN;
3895 }
3896 bcm->firmware_norelease = 1;
3897 bcm43xx_free_board(bcm);
3898 bcm->firmware_norelease = 0;
3899 }
3900 bcm43xx_chipset_detach(bcm);
3901
3902 pci_save_state(pdev);
3903 pci_disable_device(pdev);
3904 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3905
3906 dprintk(KERN_INFO PFX "Device suspended.\n");
3907
3908 return 0;
3909}
3910
3911static int bcm43xx_resume(struct pci_dev *pdev)
3912{
3913 struct net_device *net_dev = pci_get_drvdata(pdev);
3914 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3915 int err = 0;
3916
3917 dprintk(KERN_INFO PFX "Resuming...\n");
3918
3919 pci_set_power_state(pdev, 0);
3920 pci_enable_device(pdev);
3921 pci_restore_state(pdev);
3922
3923 bcm43xx_chipset_attach(bcm);
3924 if (bcm->was_initialized) {
3925 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3926 err = bcm43xx_init_board(bcm);
3927 }
3928 if (err) {
3929 printk(KERN_ERR PFX "Resume failed!\n");
3930 return err;
3931 }
3932
3933 netif_device_attach(net_dev);
3934
John W. Linvillef2223132006-01-23 16:59:58 -05003935 dprintk(KERN_INFO PFX "Device resumed.\n");
3936
3937 return 0;
3938}
3939
3940#endif /* CONFIG_PM */
3941
3942static struct pci_driver bcm43xx_pci_driver = {
Michael Buesch65f3f192006-01-31 20:11:38 +01003943 .name = KBUILD_MODNAME,
John W. Linvillef2223132006-01-23 16:59:58 -05003944 .id_table = bcm43xx_pci_tbl,
3945 .probe = bcm43xx_init_one,
3946 .remove = __devexit_p(bcm43xx_remove_one),
3947#ifdef CONFIG_PM
3948 .suspend = bcm43xx_suspend,
3949 .resume = bcm43xx_resume,
3950#endif /* CONFIG_PM */
3951};
3952
3953static int __init bcm43xx_init(void)
3954{
Michael Buesch65f3f192006-01-31 20:11:38 +01003955 printk(KERN_INFO KBUILD_MODNAME " driver\n");
John W. Linvillef2223132006-01-23 16:59:58 -05003956 bcm43xx_debugfs_init();
3957 return pci_register_driver(&bcm43xx_pci_driver);
3958}
3959
3960static void __exit bcm43xx_exit(void)
3961{
3962 pci_unregister_driver(&bcm43xx_pci_driver);
3963 bcm43xx_debugfs_exit();
3964}
3965
3966module_init(bcm43xx_init)
3967module_exit(bcm43xx_exit)