aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2006-01-23 16:59:58 -0500
committerJohn W. Linville <linville@tuxdriver.com>2006-03-27 11:18:23 -0500
commitf222313a61a5e134de80767b35c672b91e78383c (patch)
treec3a8dca8a021bd88f58112e70ce52cfb28e99ff1
parent5d5d7727a8cde78f798ecf04bac8031eff536f9d (diff)
[PATCH] wireless: import bcm43xx sources
Import the bcm43xx driver from the upstream sources here: ftp://ftp.berlios.de/pub/bcm43xx/snapshots/bcm43xx/bcm43xx-20060123.tar.bz2 Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/bcm43xx/COPYING340
-rw-r--r--drivers/net/wireless/bcm43xx/Makefile87
-rw-r--r--drivers/net/wireless/bcm43xx/README36
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h961
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c503
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h117
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.c1009
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.h176
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ilt.c367
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ilt.h34
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c261
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.h47
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c4597
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h283
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c2122
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.h74
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c592
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.h88
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_power.c358
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_power.h47
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c1766
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.h93
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c1099
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.h36
24 files changed, 15093 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcm43xx/COPYING b/drivers/net/wireless/bcm43xx/COPYING
new file mode 100644
index 000000000000..5b6e7c66c276
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/COPYING
@@ -0,0 +1,340 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Library General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License
307 along with this program; if not, write to the Free Software
308 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
309
310
311Also add information on how to contact you by electronic and paper mail.
312
313If the program is interactive, make it output a short notice like this
314when it starts in an interactive mode:
315
316 Gnomovision version 69, Copyright (C) year name of author
317 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
318 This is free software, and you are welcome to redistribute it
319 under certain conditions; type `show c' for details.
320
321The hypothetical commands `show w' and `show c' should show the appropriate
322parts of the General Public License. Of course, the commands you use may
323be called something other than `show w' and `show c'; they could even be
324mouse-clicks or menu items--whatever suits your program.
325
326You should also get your employer (if you work as a programmer) or your
327school, if any, to sign a "copyright disclaimer" for the program, if
328necessary. Here is a sample; alter the names:
329
330 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
331 `Gnomovision' (which makes passes at compilers) written by James Hacker.
332
333 <signature of Ty Coon>, 1 April 1989
334 Ty Coon, President of Vice
335
336This General Public License does not permit incorporating your program into
337proprietary programs. If your program is a subroutine library, you may
338consider it more useful to permit linking proprietary applications with the
339library. If this is what you want to do, use the GNU Library General
340Public License instead of this License.
diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile
new file mode 100644
index 000000000000..98d4efb1d12a
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/Makefile
@@ -0,0 +1,87 @@
1# Makefile for bcm43xx driver
2
3VERSION := 0.0.1
4RELEASE_NAME := bcm43xx-$(VERSION)
5
6# Optional path, where the SoftMAC subsystem is located.
7# You may set SOFTMAC_DIR in your bashrc, for example.
8SOFTMAC_DIR ?=
9
10KVER := $(shell uname -r)
11KDIR ?= /lib/modules/$(KVER)/build
12PWD := $(shell pwd)
13MODPATH := $(DESTDIR)/lib/modules/$(KVER)/kernel/drivers/net/bcm43xx
14
15# Comment/uncomment to enable/disable debugging
16DEBUG = y
17
18
19ifeq ($(DEBUG),y)
20DEBUGFS_OBJ = bcm43xx_debugfs.o
21CFLAGS += -O2 -DCONFIG_BCM43XX_DEBUG
22else
23DEBUGFS_OBJ =
24CFLAGS += -O2
25endif
26
27CFLAGS += -DBCM43xx_VERSION=$(VERSION) -I/lib/modules/$(KVER)/include
28ifneq ($(SOFTMAC_DIR),)
29CPPFLAGS := -I$(SOFTMAC_DIR) $(CPPFLAGS)
30endif
31
32ifneq ($(KERNELRELEASE),)
33# call from kernel build system
34
35obj-m := bcm43xx.o
36bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o $(DEBUGFS_OBJ) \
37 bcm43xx_radio.o bcm43xx_phy.o \
38 bcm43xx_power.o bcm43xx_wx.o \
39 bcm43xx_pio.o bcm43xx_ilt.o \
40 bcm43xx_leds.o
41
42else
43
44default: modules
45
46modules:
47 $(MAKE) -C $(KDIR) M=$(PWD) modules
48
49install: bcm43xx.ko
50 install -d $(MODPATH)
51 install -m 644 -c bcm43xx.ko $(MODPATH)
52 /sbin/depmod -a
53
54uninstall:
55 rm -rf $(MODPATH)
56 /sbin/depmod -a
57
58endif
59
60clean:
61 find . \( -name '*.ko' -o -name '*.o' -o -name '.tmp_versions' -o -name '*~' -o -name '.*.cmd' \
62 -o -name '*.mod.c' -o -name '*.tar.bz2' -o -name '*.rej' -o -name '*.orig' \)\
63 -print | xargs rm -Rf
64
65depend .depend dep:
66 $(CC) $(CFLAGS) -M *.c > .depend
67
68ifeq (.depend,$(wildcard .depend))
69include .depend
70endif
71
72DISTFILES = $(shell find . \( -not -name '.' \) -print | grep -v "\.tar\.bz2" | grep -v "\/\." )
73DISTDIR = $(RELEASE_NAME)
74
75release: clean
76 @rm -rf $(DISTDIR)
77 @mkdir $(DISTDIR)
78 @chmod 777 $(DISTDIR)
79 @for file in $(DISTFILES); do \
80 if test -d $$file; then \
81 mkdir $(DISTDIR)/$$file; \
82 else \
83 cp -p $$file $(DISTDIR)/$$file; \
84 fi; \
85 done
86 @tar -c $(DISTDIR) | bzip2 -9 > $(RELEASE_NAME).tar.bz2
87 @rm -rf $(DISTDIR)
diff --git a/drivers/net/wireless/bcm43xx/README b/drivers/net/wireless/bcm43xx/README
new file mode 100644
index 000000000000..64d9022de7fe
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/README
@@ -0,0 +1,36 @@
1
2 BCM43xx Linux Driver Project
3 ============================
4
5About this software
6-------------------
7
8The goal of this project is to develop a linux driver for Broadcom
9BCM43xx chips, based on the specification at
10http://bcm-specs.sipsolutions.net/
11
12The project page is http://bcm43xx.berlios.de/
13
14
15Requirements
16------------
17
181) Linux Kernel 2.6.15 or later
19 http://www.kernel.org/
20
21 You may want to configure your kernel with:
22
23 CONFIG_DEBUG_FS (optional):
24 -> Kernel hacking
25 -> Debug Filesystem
26
272) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
28 modules:
29 http://softmac.sipsolutions.net/
30
313) Firmware Files
32
33 Please try fwcutter. Fwcutter can extract the firmware from various
34 binary driver files. It supports driver files from Windows, MacOS and
35 Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
36 Also, fwcutter comes with a README file for further instructions.
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
new file mode 100644
index 000000000000..aca1601e5b4f
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -0,0 +1,961 @@
1#ifndef BCM43xx_H_
2#define BCM43xx_H_
3
4#include <linux/version.h>
5#include <linux/kernel.h>
6#include <linux/spinlock.h>
7#include <linux/interrupt.h>
8#include <linux/stringify.h>
9#include <linux/pci.h>
10#include <net/ieee80211.h>
11#include <net/ieee80211softmac.h>
12#include <asm/atomic.h>
13#include <asm/io.h>
14
15
16#include "bcm43xx_debugfs.h"
17#include "bcm43xx_leds.h"
18
19
20#define DRV_NAME __stringify(KBUILD_MODNAME)
21#define DRV_VERSION __stringify(BCM43xx_VERSION)
22#define BCM43xx_DRIVER_NAME DRV_NAME " driver " DRV_VERSION
23#define PFX DRV_NAME ": "
24
25#define BCM43xx_SWITCH_CORE_MAX_RETRIES 10
26#define BCM43xx_IRQWAIT_MAX_RETRIES 50
27#define BCM43xx_TX_TIMEOUT (10 * HZ)
28
29#define BCM43xx_IO_SIZE 8192
30#define BCM43xx_REG_ACTIVE_CORE 0x80
31
32/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */
33#define BCM43xx_PCICFG_ICR 0x94
34/* SPROM control register. */
35#define BCM43xx_PCICFG_SPROMCTL 0x88
36
37/* MMIO offsets */
38#define BCM43xx_MMIO_DMA1_REASON 0x20
39#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24
40#define BCM43xx_MMIO_DMA2_REASON 0x28
41#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C
42#define BCM43xx_MMIO_DMA3_REASON 0x30
43#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34
44#define BCM43xx_MMIO_DMA4_REASON 0x38
45#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C
46#define BCM43xx_MMIO_STATUS_BITFIELD 0x120
47#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124
48#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128
49#define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C
50#define BCM43xx_MMIO_RAM_CONTROL 0x130
51#define BCM43xx_MMIO_RAM_DATA 0x134
52#define BCM43xx_MMIO_PS_STATUS 0x140
53#define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158
54#define BCM43xx_MMIO_SHM_CONTROL 0x160
55#define BCM43xx_MMIO_SHM_DATA 0x164
56#define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166
57#define BCM43xx_MMIO_XMITSTAT_0 0x170
58#define BCM43xx_MMIO_XMITSTAT_1 0x174
59#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
60#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
61#define BCM43xx_MMIO_DMA1_BASE 0x200
62#define BCM43xx_MMIO_DMA2_BASE 0x220
63#define BCM43xx_MMIO_DMA3_BASE 0x240
64#define BCM43xx_MMIO_DMA4_BASE 0x260
65#define BCM43xx_MMIO_PIO1_BASE 0x300
66#define BCM43xx_MMIO_PIO2_BASE 0x310
67#define BCM43xx_MMIO_PIO3_BASE 0x320
68#define BCM43xx_MMIO_PIO4_BASE 0x330
69#define BCM43xx_MMIO_PHY_VER 0x3E0
70#define BCM43xx_MMIO_PHY_RADIO 0x3E2
71#define BCM43xx_MMIO_ANTENNA 0x3E8
72#define BCM43xx_MMIO_CHANNEL 0x3F0
73#define BCM43xx_MMIO_CHANNEL_EXT 0x3F4
74#define BCM43xx_MMIO_RADIO_CONTROL 0x3F6
75#define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8
76#define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA
77#define BCM43xx_MMIO_PHY_CONTROL 0x3FC
78#define BCM43xx_MMIO_PHY_DATA 0x3FE
79#define BCM43xx_MMIO_MACFILTER_CONTROL 0x420
80#define BCM43xx_MMIO_MACFILTER_DATA 0x422
81#define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A
82#define BCM43xx_MMIO_GPIO_CONTROL 0x49C
83#define BCM43xx_MMIO_GPIO_MASK 0x49E
84#define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */
85#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */
86#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */
87#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */
88#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8
89
90/* SPROM offsets. */
91#define BCM43xx_SPROM_BASE 0x1000
92#define BCM43xx_SPROM_BOARDFLAGS2 0x1c
93#define BCM43xx_SPROM_IL0MACADDR 0x24
94#define BCM43xx_SPROM_ET0MACADDR 0x27
95#define BCM43xx_SPROM_ET1MACADDR 0x2a
96#define BCM43xx_SPROM_ETHPHY 0x2d
97#define BCM43xx_SPROM_BOARDREV 0x2e
98#define BCM43xx_SPROM_PA0B0 0x2f
99#define BCM43xx_SPROM_PA0B1 0x30
100#define BCM43xx_SPROM_PA0B2 0x31
101#define BCM43xx_SPROM_WL0GPIO0 0x32
102#define BCM43xx_SPROM_WL0GPIO2 0x33
103#define BCM43xx_SPROM_MAXPWR 0x34
104#define BCM43xx_SPROM_PA1B0 0x35
105#define BCM43xx_SPROM_PA1B1 0x36
106#define BCM43xx_SPROM_PA1B2 0x37
107#define BCM43xx_SPROM_IDL_TSSI_TGT 0x38
108#define BCM43xx_SPROM_BOARDFLAGS 0x39
109#define BCM43xx_SPROM_ANTENNA_GAIN 0x3a
110#define BCM43xx_SPROM_VERSION 0x3f
111
112/* BCM43xx_SPROM_BOARDFLAGS values */
113#define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
114#define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
115#define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */
116#define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */
117#define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */
118#define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */
119#define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */
120#define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */
121#define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */
122#define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */
123#define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */
124#define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */
125
126/* GPIO register offset, in both ChipCommon and PCI core. */
127#define BCM43xx_GPIO_CONTROL 0x6c
128
129/* SHM Routing */
130#define BCM43xx_SHM_SHARED 0x0001
131#define BCM43xx_SHM_WIRELESS 0x0002
132#define BCM43xx_SHM_PCM 0x0003
133#define BCM43xx_SHM_HWMAC 0x0004
134#define BCM43xx_SHM_UCODE 0x0300
135
136/* MacFilter offsets. */
137#define BCM43xx_MACFILTER_SELF 0x0000
138#define BCM43xx_MACFILTER_ASSOC 0x0003
139
140/* Chipcommon registers. */
141#define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04
142#define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0
143#define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4
144#define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8
145#define BCM43xx_CHIPCOMMON_SYSCLKCTL 0xC0
146
147/* PCI core specific registers. */
148#define BCM43xx_PCICORE_BCAST_ADDR 0x50
149#define BCM43xx_PCICORE_BCAST_DATA 0x54
150#define BCM43xx_PCICORE_SBTOPCI2 0x108
151
152/* SBTOPCI2 values. */
153#define BCM43xx_SBTOPCI2_PREFETCH 0x4
154#define BCM43xx_SBTOPCI2_BURST 0x8
155
156/* Chipcommon capabilities. */
157#define BCM43xx_CAPABILITIES_PCTL 0x00040000
158#define BCM43xx_CAPABILITIES_PLLMASK 0x00030000
159#define BCM43xx_CAPABILITIES_PLLSHIFT 16
160#define BCM43xx_CAPABILITIES_FLASHMASK 0x00000700
161#define BCM43xx_CAPABILITIES_FLASHSHIFT 8
162#define BCM43xx_CAPABILITIES_EXTBUSPRESENT 0x00000040
163#define BCM43xx_CAPABILITIES_UARTGPIO 0x00000020
164#define BCM43xx_CAPABILITIES_UARTCLOCKMASK 0x00000018
165#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT 3
166#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN 0x00000004
167#define BCM43xx_CAPABILITIES_NRUARTSMASK 0x00000003
168
169/* PowerControl */
170#define BCM43xx_PCTL_IN 0xB0
171#define BCM43xx_PCTL_OUT 0xB4
172#define BCM43xx_PCTL_OUTENABLE 0xB8
173#define BCM43xx_PCTL_XTAL_POWERUP 0x40
174#define BCM43xx_PCTL_PLL_POWERDOWN 0x80
175
176/* PowerControl Clock Modes */
177#define BCM43xx_PCTL_CLK_FAST 0x00
178#define BCM43xx_PCTL_CLK_SLOW 0x01
179#define BCM43xx_PCTL_CLK_DYNAMIC 0x02
180
181#define BCM43xx_PCTL_FORCE_SLOW 0x0800
182#define BCM43xx_PCTL_FORCE_PLL 0x1000
183#define BCM43xx_PCTL_DYN_XTAL 0x2000
184
185/* COREIDs */
186#define BCM43xx_COREID_CHIPCOMMON 0x800
187#define BCM43xx_COREID_ILINE20 0x801
188#define BCM43xx_COREID_SDRAM 0x803
189#define BCM43xx_COREID_PCI 0x804
190#define BCM43xx_COREID_MIPS 0x805
191#define BCM43xx_COREID_ETHERNET 0x806
192#define BCM43xx_COREID_V90 0x807
193#define BCM43xx_COREID_USB11_HOSTDEV 0x80a
194#define BCM43xx_COREID_IPSEC 0x80b
195#define BCM43xx_COREID_PCMCIA 0x80d
196#define BCM43xx_COREID_EXT_IF 0x80f
197#define BCM43xx_COREID_80211 0x812
198#define BCM43xx_COREID_MIPS_3302 0x816
199#define BCM43xx_COREID_USB11_HOST 0x817
200#define BCM43xx_COREID_USB11_DEV 0x818
201#define BCM43xx_COREID_USB20_HOST 0x819
202#define BCM43xx_COREID_USB20_DEV 0x81a
203#define BCM43xx_COREID_SDIO_HOST 0x81b
204
205/* Core Information Registers */
206#define BCM43xx_CIR_BASE 0xf00
207#define BCM43xx_CIR_SBTPSFLAG (BCM43xx_CIR_BASE + 0x18)
208#define BCM43xx_CIR_SBIMSTATE (BCM43xx_CIR_BASE + 0x90)
209#define BCM43xx_CIR_SBINTVEC (BCM43xx_CIR_BASE + 0x94)
210#define BCM43xx_CIR_SBTMSTATELOW (BCM43xx_CIR_BASE + 0x98)
211#define BCM43xx_CIR_SBTMSTATEHIGH (BCM43xx_CIR_BASE + 0x9c)
212#define BCM43xx_CIR_SBIMCONFIGLOW (BCM43xx_CIR_BASE + 0xa8)
213#define BCM43xx_CIR_SB_ID_HI (BCM43xx_CIR_BASE + 0xfc)
214
215/* Mask to get the Backplane Flag Number from SBTPSFLAG. */
216#define BCM43xx_BACKPLANE_FLAG_NR_MASK 0x3f
217
218/* SBIMCONFIGLOW values/masks. */
219#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK 0x00000007
220#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT 0
221#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK 0x00000070
222#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT 4
223#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK 0x00ff0000
224#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT 16
225
226/* sbtmstatelow state flags */
227#define BCM43xx_SBTMSTATELOW_RESET 0x01
228#define BCM43xx_SBTMSTATELOW_REJECT 0x02
229#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000
230#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000
231
232/* sbtmstatehigh state flags */
233#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1
234#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4
235
236/* sbimstate flags */
237#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000
238#define BCM43xx_SBIMSTATE_TIMEOUT 0x40000
239
240/* PHYVersioning */
241#define BCM43xx_PHYTYPE_A 0x00
242#define BCM43xx_PHYTYPE_B 0x01
243#define BCM43xx_PHYTYPE_G 0x02
244
245/* PHYRegisters */
246#define BCM43xx_PHY_ILT_A_CTRL 0x0072
247#define BCM43xx_PHY_ILT_A_DATA1 0x0073
248#define BCM43xx_PHY_ILT_A_DATA2 0x0074
249#define BCM43xx_PHY_G_LO_CONTROL 0x0810
250#define BCM43xx_PHY_ILT_G_CTRL 0x0472
251#define BCM43xx_PHY_ILT_G_DATA1 0x0473
252#define BCM43xx_PHY_ILT_G_DATA2 0x0474
253#define BCM43xx_PHY_A_PCTL 0x007B
254#define BCM43xx_PHY_G_PCTL 0x0029
255#define BCM43xx_PHY_A_CRS 0x0029
256#define BCM43xx_PHY_RADIO_BITFIELD 0x0401
257#define BCM43xx_PHY_G_CRS 0x0429
258#define BCM43xx_PHY_NRSSILT_CTRL 0x0803
259#define BCM43xx_PHY_NRSSILT_DATA 0x0804
260
261/* RadioRegisters */
262#define BCM43xx_RADIOCTL_ID 0x01
263
264/* StatusBitField */
265#define BCM43xx_SBF_MAC_ENABLED 0x00000001
266#define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/
267#define BCM43xx_SBF_CORE_READY 0x00000004
268#define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/
269#define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/
270#define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/
271#define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000
272#define BCM43xx_SBF_MODE_NOTADHOC 0x00020000
273#define BCM43xx_SBF_MODE_AP 0x00040000
274#define BCM43xx_SBF_RADIOREG_LOCK 0x00080000
275#define BCM43xx_SBF_MODE_MONITOR 0x00400000
276#define BCM43xx_SBF_MODE_PROMISC 0x01000000
277#define BCM43xx_SBF_PS1 0x02000000
278#define BCM43xx_SBF_PS2 0x04000000
279#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000
280#define BCM43xx_SBF_TIME_UPDATE 0x10000000
281#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/
282
283/* MicrocodeFlagsBitfield (addr + lo-word values?)*/
284#define BCM43xx_UCODEFLAGS_OFFSET 0x005E
285
286#define BCM43xx_UCODEFLAG_AUTODIV 0x0001
287#define BCM43xx_UCODEFLAG_UNKBGPHY 0x0002
288#define BCM43xx_UCODEFLAG_UNKBPHY 0x0004
289#define BCM43xx_UCODEFLAG_UNKGPHY 0x0020
290#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040
291#define BCM43xx_UCODEFLAG_JAPAN 0x0080
292
293/* Generic-Interrupt reasons. */
294#define BCM43xx_IRQ_READY (1 << 0)
295#define BCM43xx_IRQ_BEACON (1 << 1)
296#define BCM43xx_IRQ_PS (1 << 2)
297#define BCM43xx_IRQ_REG124 (1 << 5)
298#define BCM43xx_IRQ_PMQ (1 << 6)
299#define BCM43xx_IRQ_PIO_WORKAROUND (1 << 8)
300#define BCM43xx_IRQ_XMIT_ERROR (1 << 11)
301#define BCM43xx_IRQ_RX (1 << 15)
302#define BCM43xx_IRQ_SCAN (1 << 16)
303#define BCM43xx_IRQ_NOISE (1 << 18)
304#define BCM43xx_IRQ_XMIT_STATUS (1 << 29)
305
306#define BCM43xx_IRQ_ALL 0xffffffff
307#define BCM43xx_IRQ_INITIAL (BCM43xx_IRQ_PS | \
308 BCM43xx_IRQ_REG124 | \
309 BCM43xx_IRQ_PMQ | \
310 BCM43xx_IRQ_XMIT_ERROR | \
311 BCM43xx_IRQ_RX | \
312 BCM43xx_IRQ_SCAN | \
313 BCM43xx_IRQ_NOISE | \
314 BCM43xx_IRQ_XMIT_STATUS)
315
316
317/* Initial default iw_mode */
318#define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA
319
320/* Values/Masks for the device TX header */
321#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001
322#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008
323#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020
324#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100
325#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800
326
327#define BCM43xx_TXHDRCTL_OFDM 0x0001
328#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010
329#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030
330#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8
331
332#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0
333#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4
334#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003
335#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0
336
337/* Bus type PCI. */
338#define BCM43xx_BUSTYPE_PCI 0
339/* Bus type Silicone Backplane Bus. */
340#define BCM43xx_BUSTYPE_SB 1
341/* Bus type PCMCIA. */
342#define BCM43xx_BUSTYPE_PCMCIA 2
343
344/* Threshold values. */
345#define BCM43xx_MIN_RTS_THRESHOLD 1U
346#define BCM43xx_MAX_RTS_THRESHOLD 2304U
347#define BCM43xx_DEFAULT_RTS_THRESHOLD BCM43xx_MAX_RTS_THRESHOLD
348
349#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7
350#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4
351
352/* Max size of a security key */
353#define BCM43xx_SEC_KEYSIZE 16
354/* Security algorithms. */
355enum {
356 BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
357 BCM43xx_SEC_ALGO_WEP,
358 BCM43xx_SEC_ALGO_UNKNOWN,
359 BCM43xx_SEC_ALGO_AES,
360 BCM43xx_SEC_ALGO_WEP104,
361 BCM43xx_SEC_ALGO_TKIP,
362};
363
364#ifdef assert
365# undef assert
366#endif
367#ifdef CONFIG_BCM43XX_DEBUG
368#define assert(expr) \
369 do { \
370 if (unlikely(!(expr))) { \
371 printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \
372 #expr, __FILE__, __LINE__, __FUNCTION__); \
373 } \
374 } while (0)
375#else
376#define assert(expr) do { /* nothing */ } while (0)
377#endif
378
379/* rate limited printk(). */
380#ifdef printkl
381# undef printkl
382#endif
383#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
384/* rate limited printk() for debugging */
385#ifdef dprintkl
386# undef dprintkl
387#endif
388#ifdef CONFIG_BCM43XX_DEBUG
389# define dprintkl printkl
390#else
391# define dprintkl(f, x...) do { /* nothing */ } while (0)
392#endif
393
394/* Helper macro for if branches.
395 * An if branch marked with this macro is only taken in DEBUG mode.
396 * Example:
397 * if (DEBUG_ONLY(foo == bar)) {
398 * do something
399 * }
400 * In DEBUG mode, the branch will be taken if (foo == bar).
401 * In non-DEBUG mode, the branch will never be taken.
402 */
403#ifdef DEBUG_ONLY
404# undef DEBUG_ONLY
405#endif
406#ifdef CONFIG_BCM43XX_DEBUG
407# define DEBUG_ONLY(x) (x)
408#else
409# define DEBUG_ONLY(x) 0
410#endif
411
412/* debugging printk() */
413#ifdef dprintk
414# undef dprintk
415#endif
416#ifdef CONFIG_BCM43XX_DEBUG
417# define dprintk(f, x...) do { printk(f ,##x); } while (0)
418#else
419# define dprintk(f, x...) do { /* nothing */ } while (0)
420#endif
421
422
423struct net_device;
424struct pci_dev;
425struct workqueue_struct;
426struct bcm43xx_dmaring;
427struct bcm43xx_pioqueue;
428
429struct bcm43xx_initval {
430 u16 offset;
431 u16 size;
432 u32 value;
433} __attribute__((__packed__));
434
435/* Values for bcm430x_sprominfo.locale */
436enum {
437 BCM43xx_LOCALE_WORLD = 0,
438 BCM43xx_LOCALE_THAILAND,
439 BCM43xx_LOCALE_ISRAEL,
440 BCM43xx_LOCALE_JORDAN,
441 BCM43xx_LOCALE_CHINA,
442 BCM43xx_LOCALE_JAPAN,
443 BCM43xx_LOCALE_USA_CANADA_ANZ,
444 BCM43xx_LOCALE_EUROPE,
445 BCM43xx_LOCALE_USA_LOW,
446 BCM43xx_LOCALE_JAPAN_HIGH,
447 BCM43xx_LOCALE_ALL,
448 BCM43xx_LOCALE_NONE,
449};
450
451#define BCM43xx_SPROM_SIZE 64 /* in 16-bit words. */
452struct bcm43xx_sprominfo {
453 u16 boardflags2;
454 u8 il0macaddr[6];
455 u8 et0macaddr[6];
456 u8 et1macaddr[6];
457 u8 et0phyaddr:5;
458 u8 et1phyaddr:5;
459 u8 et0mdcport:1;
460 u8 et1mdcport:1;
461 u8 boardrev;
462 u8 locale:4;
463 u8 antennas_aphy:2;
464 u8 antennas_bgphy:2;
465 u16 pa0b0;
466 u16 pa0b1;
467 u16 pa0b2;
468 u8 wl0gpio0;
469 u8 wl0gpio1;
470 u8 wl0gpio2;
471 u8 wl0gpio3;
472 u8 maxpower_aphy;
473 u8 maxpower_bgphy;
474 u16 pa1b0;
475 u16 pa1b1;
476 u16 pa1b2;
477 u8 idle_tssi_tgt_aphy;
478 u8 idle_tssi_tgt_bgphy;
479 u16 boardflags;
480 u16 antennagain_aphy;
481 u16 antennagain_bgphy;
482};
483
484/* Value pair to measure the LocalOscillator. */
485struct bcm43xx_lopair {
486 s8 low;
487 s8 high;
488 u8 used:1;
489};
490#define BCM43xx_LO_COUNT (14*4)
491
492struct bcm43xx_phyinfo {
493 /* Hardware Data */
494 u8 version;
495 u8 type;
496 u8 rev;
497 u16 antenna_diversity;
498 u16 savedpctlreg;
499 u16 minlowsig[2];
500 u16 minlowsigpos[2];
501 u8 connected:1,
502 calibrated:1,
503 is_locked:1, /* used in bcm43xx_phy_{un}lock() */
504 dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */
505 /* LO Measurement Data.
506 * Use bcm43xx_get_lopair() to get a value.
507 */
508 struct bcm43xx_lopair *_lo_pairs;
509
510 /* TSSI to dBm table in use */
511 const s8 *tssi2dbm;
512 /* idle TSSI value */
513 s8 idle_tssi;
514 /* PHY lock for core.rev < 3
515 * This lock is only used by bcm43xx_phy_{un}lock()
516 */
517 spinlock_t lock;
518};
519
520
521struct bcm43xx_radioinfo {
522 u16 manufact;
523 u16 version;
524 u8 revision;
525
526 /* 0: baseband attenuation,
527 * 1: radio attenuation,
528 * 2: tx_CTL1
529 * 3: tx_CTL2
530 */
531 u16 txpower[4];
532 /* Current Interference Mitigation mode */
533 int interfmode;
534 /* Stack of saved values from the Interference Mitigation code */
535 u16 interfstack[20];
536 /* Saved values from the NRSSI Slope calculation */
537 s16 nrssi[2];
538 s32 nrssislope;
539 /* In memory nrssi lookup table. */
540 s8 nrssi_lt[64];
541
542 /* current channel */
543 u8 channel;
544 u8 initial_channel;
545
546 u16 lofcal;
547
548 u16 initval;
549
550 u8 enabled:1;
551 /* ACI (adjacent channel interference) flags. */
552 u8 aci_enable:1,
553 aci_wlan_automatic:1,
554 aci_hw_rssi:1;
555};
556
557/* Data structures for DMA transmission, per 80211 core. */
558struct bcm43xx_dma {
559 struct bcm43xx_dmaring *tx_ring0;
560 struct bcm43xx_dmaring *tx_ring1;
561 struct bcm43xx_dmaring *tx_ring2;
562 struct bcm43xx_dmaring *tx_ring3;
563 struct bcm43xx_dmaring *rx_ring0;
564 struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
565};
566
567/* Data structures for PIO transmission, per 80211 core. */
568struct bcm43xx_pio {
569 struct bcm43xx_pioqueue *queue0;
570 struct bcm43xx_pioqueue *queue1;
571 struct bcm43xx_pioqueue *queue2;
572 struct bcm43xx_pioqueue *queue3;
573};
574
575#define BCM43xx_MAX_80211_CORES 2
576
577#define BCM43xx_COREFLAG_AVAILABLE (1 << 0)
578#define BCM43xx_COREFLAG_ENABLED (1 << 1)
579#define BCM43xx_COREFLAG_INITIALIZED (1 << 2)
580
581#ifdef CONFIG_BCM947XX
582#define core_offset(bcm) (bcm)->current_core_offset
583#else
584#define core_offset(bcm) 0
585#endif
586
587struct bcm43xx_coreinfo {
588 /** Driver internal flags. See BCM43xx_COREFLAG_* */
589 u32 flags;
590 /** core_id ID number */
591 u16 id;
592 /** core_rev revision number */
593 u8 rev;
594 /** Index number for _switch_core() */
595 u8 index;
596 /* Pointer to the PHYinfo, which belongs to this core (if 80211 core) */
597 struct bcm43xx_phyinfo *phy;
598 /* Pointer to the RadioInfo, which belongs to this core (if 80211 core) */
599 struct bcm43xx_radioinfo *radio;
600 /* Pointer to the DMA rings, which belong to this core (if 80211 core) */
601 struct bcm43xx_dma *dma;
602 /* Pointer to the PIO queues, which belong to this core (if 80211 core) */
603 struct bcm43xx_pio *pio;
604};
605
606/* Context information for a noise calculation (Link Quality). */
607struct bcm43xx_noise_calculation {
608 struct bcm43xx_coreinfo *core_at_start;
609 u8 channel_at_start;
610 u8 calculation_running:1;
611 u8 nr_samples;
612 s8 samples[8][4];
613};
614
615struct bcm43xx_stats {
616 u8 link_quality;
617 /* Store the last TX/RX times here for updating the leds. */
618 unsigned long last_tx;
619 unsigned long last_rx;
620};
621
622struct bcm43xx_key {
623 u8 enabled:1;
624 u8 algorithm;
625};
626
627struct bcm43xx_private {
628 struct ieee80211_device *ieee;
629 struct ieee80211softmac_device *softmac;
630
631 struct net_device *net_dev;
632 struct pci_dev *pci_dev;
633 unsigned int irq;
634
635 void __iomem *mmio_addr;
636 unsigned int mmio_len;
637
638 spinlock_t lock;
639
640 /* Driver status flags. */
641 u32 initialized:1, /* init_board() succeed */
642 was_initialized:1, /* for PCI suspend/resume. */
643 shutting_down:1, /* free_board() in progress */
644 pio_mode:1, /* PIO (if true), or DMA (if false) used. */
645 bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
646 reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
647 powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */
648 short_preamble:1, /* TRUE, if short preamble is enabled. */
649 firmware_norelease:1; /* Do not release the firmware. Used on suspend. */
650
651 struct bcm43xx_stats stats;
652
653 /* Bus type we are connected to.
654 * This is currently always BCM43xx_BUSTYPE_PCI
655 */
656 u8 bustype;
657
658 u16 board_vendor;
659 u16 board_type;
660 u16 board_revision;
661
662 u16 chip_id;
663 u8 chip_rev;
664
665 struct bcm43xx_sprominfo sprom;
666#define BCM43xx_NR_LEDS 4
667 struct bcm43xx_led leds[BCM43xx_NR_LEDS];
668
669 /* The currently active core. NULL if not initialized, yet. */
670 struct bcm43xx_coreinfo *current_core;
671#ifdef CONFIG_BCM947XX
672 /** current core memory offset */
673 u32 current_core_offset;
674#endif
675 struct bcm43xx_coreinfo *active_80211_core;
676 /* coreinfo structs for all possible cores follow.
677 * Note that a core might not exist.
678 * So check the coreinfo flags before using it.
679 */
680 struct bcm43xx_coreinfo core_chipcommon;
681 struct bcm43xx_coreinfo core_pci;
682 struct bcm43xx_coreinfo core_v90;
683 struct bcm43xx_coreinfo core_pcmcia;
684 struct bcm43xx_coreinfo core_ethernet;
685 struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
686 /* Info about the PHY for each 80211 core. */
687 struct bcm43xx_phyinfo phy[ BCM43xx_MAX_80211_CORES ];
688 /* Info about the Radio for each 80211 core. */
689 struct bcm43xx_radioinfo radio[ BCM43xx_MAX_80211_CORES ];
690 /* DMA */
691 struct bcm43xx_dma dma[ BCM43xx_MAX_80211_CORES ];
692 /* PIO */
693 struct bcm43xx_pio pio[ BCM43xx_MAX_80211_CORES ];
694
695 u32 chipcommon_capabilities;
696
697 /* Reason code of the last interrupt. */
698 u32 irq_reason;
699 u32 dma_reason[4];
700 /* saved irq enable/disable state bitfield. */
701 u32 irq_savedstate;
702 /* Link Quality calculation context. */
703 struct bcm43xx_noise_calculation noisecalc;
704
705 /* Threshold values. */
706 //TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
707 u32 rts_threshold;
708
709 /* Interrupt Service Routine tasklet (bottom-half) */
710 struct tasklet_struct isr_tasklet;
711 /* Custom driver work queue. */
712 struct workqueue_struct *workqueue;
713
714 /* Periodic tasks */
715 struct work_struct periodic_work0;
716#define BCM43xx_PERIODIC_0_DELAY (HZ * 15)
717 struct work_struct periodic_work1;
718#define BCM43xx_PERIODIC_1_DELAY ((HZ * 60) + HZ / 2)
719 struct work_struct periodic_work2;
720#define BCM43xx_PERIODIC_2_DELAY ((HZ * 120) + HZ)
721 struct work_struct periodic_work3;
722#define BCM43xx_PERIODIC_3_DELAY ((HZ * 30) + HZ / 5)
723
724 struct work_struct restart_work;
725
726 /* Informational stuff. */
727 char nick[IW_ESSID_MAX_SIZE + 1];
728
729 /* encryption/decryption */
730 u16 security_offset;
731 struct bcm43xx_key key[54];
732 u8 default_key_idx;
733
734 /* Firmware. */
735 const struct firmware *ucode;
736 const struct firmware *pcm;
737 const struct firmware *initvals0;
738 const struct firmware *initvals1;
739
740 /* Debugging stuff follows. */
741#ifdef CONFIG_BCM43XX_DEBUG
742 struct bcm43xx_dfsentry *dfsentry;
743 atomic_t mmio_print_cnt;
744 atomic_t pcicfg_print_cnt;
745#endif
746};
747
748static inline
749struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
750{
751 return ieee80211softmac_priv(dev);
752}
753
754static inline
755int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm)
756{
757 int i, cnt = 0;
758
759 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
760 if (bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)
761 cnt++;
762 }
763
764 return cnt;
765}
766
767/* Are we running in init_board() context? */
768static inline
769int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
770{
771 if (bcm->initialized)
772 return 0;
773 if (bcm->shutting_down)
774 return 0;
775 return 1;
776}
777
778static inline
779struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
780 u16 radio_attenuation,
781 u16 baseband_attenuation)
782{
783 return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2));
784}
785
786
787/* MMIO read/write functions. Debug and non-debug variants. */
788#ifdef CONFIG_BCM43XX_DEBUG
789
790static inline
791u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
792{
793 u16 value;
794
795 value = ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
796 if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) {
797 printk(KERN_INFO PFX "ioread16 offset: 0x%04x, value: 0x%04x\n",
798 offset, value);
799 }
800
801 return value;
802}
803
804static inline
805void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
806{
807 iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
808 if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) {
809 printk(KERN_INFO PFX "iowrite16 offset: 0x%04x, value: 0x%04x\n",
810 offset, value);
811 }
812}
813
814static inline
815u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
816{
817 u32 value;
818
819 value = ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
820 if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) {
821 printk(KERN_INFO PFX "ioread32 offset: 0x%04x, value: 0x%08x\n",
822 offset, value);
823 }
824
825 return value;
826}
827
828static inline
829void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
830{
831 iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
832 if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) {
833 printk(KERN_INFO PFX "iowrite32 offset: 0x%04x, value: 0x%08x\n",
834 offset, value);
835 }
836}
837
838static inline
839int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value)
840{
841 int err;
842
843 err = pci_read_config_word(bcm->pci_dev, offset, value);
844 if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) {
845 printk(KERN_INFO PFX "pciread16 offset: 0x%08x, value: 0x%04x, err: %d\n",
846 offset, *value, err);
847 }
848
849 return err;
850}
851
852static inline
853int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value)
854{
855 int err;
856
857 err = pci_read_config_dword(bcm->pci_dev, offset, value);
858 if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) {
859 printk(KERN_INFO PFX "pciread32 offset: 0x%08x, value: 0x%08x, err: %d\n",
860 offset, *value, err);
861 }
862
863 return err;
864}
865
866static inline
867int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value)
868{
869 int err;
870
871 err = pci_write_config_word(bcm->pci_dev, offset, value);
872 if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) {
873 printk(KERN_INFO PFX "pciwrite16 offset: 0x%08x, value: 0x%04x, err: %d\n",
874 offset, value, err);
875 }
876
877 return err;
878}
879
880static inline
881int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value)
882{
883 int err;
884
885 err = pci_write_config_dword(bcm->pci_dev, offset, value);
886 if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) {
887 printk(KERN_INFO PFX "pciwrite32 offset: 0x%08x, value: 0x%08x, err: %d\n",
888 offset, value, err);
889 }
890
891 return err;
892}
893
894#define bcm43xx_mmioprint_initial(bcm, value) atomic_set(&(bcm)->mmio_print_cnt, (value))
895#define bcm43xx_mmioprint_enable(bcm) atomic_inc(&(bcm)->mmio_print_cnt)
896#define bcm43xx_mmioprint_disable(bcm) atomic_dec(&(bcm)->mmio_print_cnt)
897#define bcm43xx_pciprint_initial(bcm, value) atomic_set(&(bcm)->pcicfg_print_cnt, (value))
898#define bcm43xx_pciprint_enable(bcm) atomic_inc(&(bcm)->pcicfg_print_cnt)
899#define bcm43xx_pciprint_disable(bcm) atomic_dec(&(bcm)->pcicfg_print_cnt)
900
901#else /* CONFIG_BCM43XX_DEBUG*/
902
903#define bcm43xx_read16(bcm, offset) ioread16((bcm)->mmio_addr + core_offset(bcm) + (offset))
904#define bcm43xx_write16(bcm, offset, value) iowrite16((value), (bcm)->mmio_addr + core_offset(bcm) + (offset))
905#define bcm43xx_read32(bcm, offset) ioread32((bcm)->mmio_addr + core_offset(bcm) + (offset))
906#define bcm43xx_write32(bcm, offset, value) iowrite32((value), (bcm)->mmio_addr + core_offset(bcm) + (offset))
907#define bcm43xx_pci_read_config16(bcm, o, v) pci_read_config_word((bcm)->pci_dev, (o), (v))
908#define bcm43xx_pci_read_config32(bcm, o, v) pci_read_config_dword((bcm)->pci_dev, (o), (v))
909#define bcm43xx_pci_write_config16(bcm, o, v) pci_write_config_word((bcm)->pci_dev, (o), (v))
910#define bcm43xx_pci_write_config32(bcm, o, v) pci_write_config_dword((bcm)->pci_dev, (o), (v))
911
912#define bcm43xx_mmioprint_initial(x, y) do { /* nothing */ } while (0)
913#define bcm43xx_mmioprint_enable(x) do { /* nothing */ } while (0)
914#define bcm43xx_mmioprint_disable(x) do { /* nothing */ } while (0)
915#define bcm43xx_pciprint_initial(bcm, value) do { /* nothing */ } while (0)
916#define bcm43xx_pciprint_enable(bcm) do { /* nothing */ } while (0)
917#define bcm43xx_pciprint_disable(bcm) do { /* nothing */ } while (0)
918
919#endif /* CONFIG_BCM43XX_DEBUG*/
920
921
922/** Limit a value between two limits */
923#ifdef limit_value
924# undef limit_value
925#endif
926#define limit_value(value, min, max) \
927 ({ \
928 typeof(value) __value = (value); \
929 typeof(value) __min = (min); \
930 typeof(value) __max = (max); \
931 if (__value < __min) \
932 __value = __min; \
933 else if (__value > __max) \
934 __value = __max; \
935 __value; \
936 })
937
938
939/*
940 * Compatibility stuff follows
941 */
942
943#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
944# error "The bcm43xx driver does not support kernels < 2.6.15"
945# error "The driver will _NOT_ compile on your kernel. Please upgrade to the latest 2.6 kernel."
946# error "DO NOT COMPLAIN ABOUT BUGS. UPDATE FIRST AND TRY AGAIN."
947#else
948# if !defined(CONFIG_IEEE80211_MODULE) && !defined(CONFIG_IEEE80211)
949# error "Generic IEEE 802.11 Networking Stack (CONFIG_IEEE80211) not available."
950# endif
951#endif
952#ifdef IEEE80211SOFTMAC_API
953# if IEEE80211SOFTMAC_API != 0
954# warning "Incompatible SoftMAC subsystem installed."
955# endif
956#else
957# error "The bcm43xx driver requires the SoftMAC subsystem."
958# error "SEE >>>>>> http://softmac.sipsolutions.net/ <<<<<<"
959#endif
960
961#endif /* BCM43xx_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
new file mode 100644
index 000000000000..f8cfc84ca0da
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -0,0 +1,503 @@
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 debugfs driver debugging code
6
7 Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23
24*/
25
26
27
28#include <linux/fs.h>
29#include <linux/debugfs.h>
30#include <linux/slab.h>
31#include <linux/netdevice.h>
32#include <linux/pci.h>
33#include <asm/io.h>
34
35#include "bcm43xx.h"
36#include "bcm43xx_main.h"
37#include "bcm43xx_debugfs.h"
38#include "bcm43xx_dma.h"
39#include "bcm43xx_pio.h"
40
41#define REALLY_BIG_BUFFER_SIZE (1024*256)
42
43static struct bcm43xx_debugfs fs;
44static char really_big_buffer[REALLY_BIG_BUFFER_SIZE];
45static DECLARE_MUTEX(big_buffer_sem);
46
47
48static ssize_t write_file_dummy(struct file *file, const char __user *buf,
49 size_t count, loff_t *ppos)
50{
51 return count;
52}
53
54static int open_file_generic(struct inode *inode, struct file *file)
55{
56 file->private_data = inode->u.generic_ip;
57 return 0;
58}
59
60#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x)
61
62static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
63 size_t count, loff_t *ppos)
64{
65 const size_t len = REALLY_BIG_BUFFER_SIZE;
66
67 struct bcm43xx_private *bcm = file->private_data;
68 char *buf = really_big_buffer;
69 size_t pos = 0;
70 ssize_t res;
71 struct net_device *net_dev;
72 struct pci_dev *pci_dev;
73 unsigned long flags;
74 u16 tmp16;
75 int i;
76
77 down(&big_buffer_sem);
78
79 spin_lock_irqsave(&bcm->lock, flags);
80 if (!bcm->initialized) {
81 fappend("Board not initialized.\n");
82 goto out;
83 }
84 net_dev = bcm->net_dev;
85 pci_dev = bcm->pci_dev;
86
87 /* This is where the information is written to the "devinfo" file */
88 fappend("*** %s devinfo ***\n", net_dev->name);
89 fappend("vendor: 0x%04x device: 0x%04x\n",
90 pci_dev->vendor, pci_dev->device);
91 fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n",
92 pci_dev->subsystem_vendor, pci_dev->subsystem_device);
93 fappend("IRQ: %d\n", bcm->irq);
94 fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len);
95 fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
96 if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
97 fappend("Radio disabled by hardware!\n");
98 if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4)))
99 fappend("Radio disabled by hardware!\n");
100 fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor,
101 bcm->board_type);
102
103 fappend("\nCores:\n");
104#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \
105 "rev: 0x%02x, index: 0x%02x\n", \
106 (info).flags & BCM43xx_COREFLAG_AVAILABLE \
107 ? "available" : "nonavailable", \
108 (info).flags & BCM43xx_COREFLAG_ENABLED \
109 ? "enabled" : "disabled", \
110 (info).id, (info).rev, (info).index)
111 fappend_core("CHIPCOMMON", bcm->core_chipcommon);
112 fappend_core("PCI", bcm->core_pci);
113 fappend_core("V90", bcm->core_v90);
114 fappend_core("PCMCIA", bcm->core_pcmcia);
115 fappend_core("ETHERNET", bcm->core_ethernet);
116 fappend_core("first 80211", bcm->core_80211[0]);
117 fappend_core("second 80211", bcm->core_80211[1]);
118#undef fappend_core
119 tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
120 fappend("LEDs: ");
121 for (i = 0; i < BCM43xx_NR_LEDS; i++)
122 fappend("%d ", !!(tmp16 & (1 << i)));
123 fappend("\n");
124
125out:
126 spin_unlock_irqrestore(&bcm->lock, flags);
127 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
128 up(&big_buffer_sem);
129 return res;
130}
131
132static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf,
133 size_t count, loff_t *ppos)
134{
135 const size_t len = REALLY_BIG_BUFFER_SIZE;
136
137 char *buf = really_big_buffer;
138 size_t pos = 0;
139 ssize_t res;
140
141 down(&big_buffer_sem);
142
143 /* This is where the information is written to the "driver" file */
144 fappend(BCM43xx_DRIVER_NAME "\n");
145 fappend("Compiled at: %s %s\n", __DATE__, __TIME__);
146
147 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
148 up(&big_buffer_sem);
149 return res;
150}
151
152static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
153 size_t count, loff_t *ppos)
154{
155 const size_t len = REALLY_BIG_BUFFER_SIZE;
156
157 struct bcm43xx_private *bcm = file->private_data;
158 char *buf = really_big_buffer;
159 size_t pos = 0;
160 ssize_t res;
161 unsigned long flags;
162
163 down(&big_buffer_sem);
164 spin_lock_irqsave(&bcm->lock, flags);
165 if (!bcm->initialized) {
166 fappend("Board not initialized.\n");
167 goto out;
168 }
169
170 /* This is where the information is written to the "sprom_dump" file */
171 fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
172
173out:
174 spin_unlock_irqrestore(&bcm->lock, flags);
175 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
176 up(&big_buffer_sem);
177 return res;
178}
179
180static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
181 size_t count, loff_t *ppos)
182{
183 const size_t len = REALLY_BIG_BUFFER_SIZE;
184
185 struct bcm43xx_private *bcm = file->private_data;
186 char *buf = really_big_buffer;
187 size_t pos = 0;
188 ssize_t res;
189 unsigned long flags;
190 u64 tsf;
191
192 down(&big_buffer_sem);
193 spin_lock_irqsave(&bcm->lock, flags);
194 if (!bcm->initialized) {
195 fappend("Board not initialized.\n");
196 goto out;
197 }
198 bcm43xx_tsf_read(bcm, &tsf);
199 fappend("0x%08x%08x\n",
200 (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
201 (unsigned int)(tsf & 0xFFFFFFFFULL));
202
203out:
204 spin_unlock_irqrestore(&bcm->lock, flags);
205 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
206 up(&big_buffer_sem);
207 return res;
208}
209
210static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
211 size_t count, loff_t *ppos)
212{
213 struct bcm43xx_private *bcm = file->private_data;
214 char *buf = really_big_buffer;
215 ssize_t buf_size;
216 ssize_t res;
217 unsigned long flags;
218 u64 tsf;
219
220 buf_size = min(count, sizeof (really_big_buffer) - 1);
221 down(&big_buffer_sem);
222 if (copy_from_user(buf, user_buf, buf_size)) {
223 res = -EFAULT;
224 goto out_up;
225 }
226 spin_lock_irqsave(&bcm->lock, flags);
227 if (!bcm->initialized) {
228 printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
229 res = -EFAULT;
230 goto out_unlock;
231 }
232 if (sscanf(buf, "%lli", &tsf) != 1) {
233 printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n");
234 res = -EINVAL;
235 goto out_unlock;
236 }
237 bcm43xx_tsf_write(bcm, tsf);
238 res = buf_size;
239
240out_unlock:
241 spin_unlock_irqrestore(&bcm->lock, flags);
242out_up:
243 up(&big_buffer_sem);
244 return res;
245}
246
247static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
248 size_t count, loff_t *ppos)
249{
250 const size_t len = REALLY_BIG_BUFFER_SIZE;
251
252 struct bcm43xx_private *bcm = file->private_data;
253 char *buf = really_big_buffer;
254 size_t pos = 0;
255 ssize_t res;
256 unsigned long flags;
257 struct bcm43xx_dfsentry *e;
258 struct bcm43xx_xmitstatus *status;
259 int i, cnt, j = 0;
260
261 down(&big_buffer_sem);
262 spin_lock_irqsave(&bcm->lock, flags);
263
264 fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
265 BCM43xx_NR_LOGGED_XMITSTATUS);
266 e = bcm->dfsentry;
267 if (e->xmitstatus_printing == 0) {
268 /* At the beginning, make a copy of all data to avoid
269 * concurrency, as this function is called multiple
270 * times for big logs. Without copying, the data might
271 * change between reads. This would result in total trash.
272 */
273 e->xmitstatus_printing = 1;
274 e->saved_xmitstatus_ptr = e->xmitstatus_ptr;
275 e->saved_xmitstatus_cnt = e->xmitstatus_cnt;
276 memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer,
277 BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer)));
278 }
279 i = e->saved_xmitstatus_ptr - 1;
280 if (i < 0)
281 i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
282 cnt = e->saved_xmitstatus_cnt;
283 while (cnt) {
284 status = e->xmitstatus_print_buffer + i;
285 fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, "
286 "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, "
287 "unk: 0x%04x\n", j,
288 status->cookie, status->flags,
289 status->cnt1, status->cnt2, status->seq,
290 status->unknown);
291 j++;
292 cnt--;
293 i--;
294 if (i < 0)
295 i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
296 }
297
298 spin_unlock_irqrestore(&bcm->lock, flags);
299 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
300 spin_lock_irqsave(&bcm->lock, flags);
301 if (*ppos == pos) {
302 /* Done. Drop the copied data. */
303 e->xmitstatus_printing = 0;
304 }
305 spin_unlock_irqrestore(&bcm->lock, flags);
306 up(&big_buffer_sem);
307 return res;
308}
309
310#undef fappend
311
312
313static struct file_operations devinfo_fops = {
314 .read = devinfo_read_file,
315 .write = write_file_dummy,
316 .open = open_file_generic,
317};
318
319static struct file_operations spromdump_fops = {
320 .read = spromdump_read_file,
321 .write = write_file_dummy,
322 .open = open_file_generic,
323};
324
325static struct file_operations drvinfo_fops = {
326 .read = drvinfo_read_file,
327 .write = write_file_dummy,
328 .open = open_file_generic,
329};
330
331static struct file_operations tsf_fops = {
332 .read = tsf_read_file,
333 .write = tsf_write_file,
334 .open = open_file_generic,
335};
336
337static struct file_operations txstat_fops = {
338 .read = txstat_read_file,
339 .write = write_file_dummy,
340 .open = open_file_generic,
341};
342
343
344void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
345{
346 struct bcm43xx_dfsentry *e;
347 char devdir[IFNAMSIZ];
348
349 assert(bcm);
350 e = kzalloc(sizeof(*e), GFP_KERNEL);
351 if (!e) {
352 printk(KERN_ERR PFX "out of memory\n");
353 return;
354 }
355 e->bcm = bcm;
356 e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
357 * sizeof(*(e->xmitstatus_buffer)),
358 GFP_KERNEL);
359 if (!e->xmitstatus_buffer) {
360 printk(KERN_ERR PFX "out of memory\n");
361 kfree(e);
362 return;
363 }
364 e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
365 * sizeof(*(e->xmitstatus_buffer)),
366 GFP_KERNEL);
367 if (!e->xmitstatus_print_buffer) {
368 printk(KERN_ERR PFX "out of memory\n");
369 kfree(e);
370 return;
371 }
372
373
374 bcm->dfsentry = e;
375
376 strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir));
377 e->subdir = debugfs_create_dir(devdir, fs.root);
378 e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir,
379 bcm, &devinfo_fops);
380 if (!e->dentry_devinfo)
381 printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir);
382 e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir,
383 bcm, &spromdump_fops);
384 if (!e->dentry_spromdump)
385 printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir);
386 e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir,
387 bcm, &tsf_fops);
388 if (!e->dentry_tsf)
389 printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
390 e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
391 bcm, &txstat_fops);
392 if (!e->dentry_txstat)
393 printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
394}
395
396void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
397{
398 struct bcm43xx_dfsentry *e;
399
400 if (!bcm)
401 return;
402
403 e = bcm->dfsentry;
404 assert(e);
405 debugfs_remove(e->dentry_spromdump);
406 debugfs_remove(e->dentry_devinfo);
407 debugfs_remove(e->dentry_tsf);
408 debugfs_remove(e->dentry_txstat);
409 debugfs_remove(e->subdir);
410 kfree(e->xmitstatus_buffer);
411 kfree(e->xmitstatus_print_buffer);
412 kfree(e);
413}
414
415void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
416 struct bcm43xx_xmitstatus *status)
417{
418 struct bcm43xx_dfsentry *e;
419 struct bcm43xx_xmitstatus *savedstatus;
420
421 /* This is protected by bcm->lock */
422 e = bcm->dfsentry;
423 assert(e);
424 savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr;
425 memcpy(savedstatus, status, sizeof(*status));
426 e->xmitstatus_ptr++;
427 if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS)
428 e->xmitstatus_ptr = 0;
429 if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS)
430 e->xmitstatus_cnt++;
431}
432
433void bcm43xx_debugfs_init(void)
434{
435 memset(&fs, 0, sizeof(fs));
436 fs.root = debugfs_create_dir(DRV_NAME, NULL);
437 if (!fs.root)
438 printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "\" subdir failed!\n");
439 fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
440 if (!fs.dentry_driverinfo)
441 printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "/driver\" failed!\n");
442}
443
444void bcm43xx_debugfs_exit(void)
445{
446 debugfs_remove(fs.dentry_driverinfo);
447 debugfs_remove(fs.root);
448}
449
450void bcm43xx_printk_dump(const char *data,
451 size_t size,
452 const char *description)
453{
454 size_t i;
455 char c;
456
457 printk(KERN_INFO PFX "Data dump (%s, %u bytes):",
458 description, size);
459 for (i = 0; i < size; i++) {
460 c = data[i];
461 if (i % 8 == 0)
462 printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff);
463 else
464 printk("0x%02x, ", c & 0xff);
465 }
466 printk("\n");
467}
468
469void bcm43xx_printk_bitdump(const unsigned char *data,
470 size_t bytes, int msb_to_lsb,
471 const char *description)
472{
473 size_t i;
474 int j;
475 const unsigned char *d;
476
477 printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***",
478 description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
479 for (i = 0; i < bytes; i++) {
480 d = data + i;
481 if (i % 8 == 0)
482 printk("\n" KERN_INFO PFX "0x%08x: ", i);
483 if (msb_to_lsb) {
484 for (j = 7; j >= 0; j--) {
485 if (*d & (1 << j))
486 printk("1");
487 else
488 printk("0");
489 }
490 } else {
491 for (j = 0; j < 8; j++) {
492 if (*d & (1 << j))
493 printk("1");
494 else
495 printk("0");
496 }
497 }
498 printk(" ");
499 }
500 printk("\n");
501}
502
503/* vim: set ts=8 sw=8 sts=8: */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
new file mode 100644
index 000000000000..50ce267f794d
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
@@ -0,0 +1,117 @@
1#ifndef BCM43xx_DEBUGFS_H_
2#define BCM43xx_DEBUGFS_H_
3
4struct bcm43xx_private;
5struct bcm43xx_xmitstatus;
6
7#ifdef CONFIG_BCM43XX_DEBUG
8
9#include <linux/list.h>
10#include <asm/semaphore.h>
11
12struct dentry;
13
14/* limited by the size of the "really_big_buffer" */
15#define BCM43xx_NR_LOGGED_XMITSTATUS 100
16
17struct bcm43xx_dfsentry {
18 struct dentry *subdir;
19 struct dentry *dentry_devinfo;
20 struct dentry *dentry_spromdump;
21 struct dentry *dentry_tsf;
22 struct dentry *dentry_txstat;
23
24 struct bcm43xx_private *bcm;
25
26 /* saved xmitstatus. */
27 struct bcm43xx_xmitstatus *xmitstatus_buffer;
28 int xmitstatus_ptr;
29 int xmitstatus_cnt;
30 /* We need a seperate buffer while printing to avoid
31 * concurrency issues. (New xmitstatus can arrive
32 * while we are printing).
33 */
34 struct bcm43xx_xmitstatus *xmitstatus_print_buffer;
35 int saved_xmitstatus_ptr;
36 int saved_xmitstatus_cnt;
37 int xmitstatus_printing;
38};
39
40struct bcm43xx_debugfs {
41 struct dentry *root;
42 struct dentry *dentry_driverinfo;
43};
44
45void bcm43xx_debugfs_init(void);
46void bcm43xx_debugfs_exit(void);
47void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm);
48void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm);
49void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
50 struct bcm43xx_xmitstatus *status);
51
52/* Debug helper: Dump binary data through printk. */
53void bcm43xx_printk_dump(const char *data,
54 size_t size,
55 const char *description);
56/* Debug helper: Dump bitwise binary data through printk. */
57void bcm43xx_printk_bitdump(const unsigned char *data,
58 size_t bytes, int msb_to_lsb,
59 const char *description);
60#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \
61 do { \
62 bcm43xx_printk_bitdump((const unsigned char *)(pointer), \
63 sizeof(*(pointer)), \
64 (msb_to_lsb), \
65 (description)); \
66 } while (0)
67
68#else /* CONFIG_BCM43XX_DEBUG*/
69
70static inline
71void bcm43xx_debugfs_init(void) { }
72static inline
73void bcm43xx_debugfs_exit(void) { }
74static inline
75void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { }
76static inline
77void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { }
78static inline
79void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
80 struct bcm43xx_xmitstatus *status) { }
81
82static inline
83void bcm43xx_printk_dump(const char *data,
84 size_t size,
85 const char *description)
86{
87}
88static inline
89void bcm43xx_printk_bitdump(const unsigned char *data,
90 size_t bytes, int msb_to_lsb,
91 const char *description)
92{
93}
94#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0)
95
96#endif /* CONFIG_BCM43XX_DEBUG*/
97
98/* Ugly helper macros to make incomplete code more verbose on runtime */
99#ifdef TODO
100# undef TODO
101#endif
102#define TODO() \
103 do { \
104 printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \
105 __FUNCTION__, __FILE__, __LINE__); \
106 } while (0)
107
108#ifdef FIXME
109# undef FIXME
110#endif
111#define FIXME() \
112 do { \
113 printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \
114 __FUNCTION__, __FILE__, __LINE__); \
115 } while (0)
116
117#endif /* BCM43xx_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
new file mode 100644
index 000000000000..df19fbfa9ea1
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -0,0 +1,1009 @@
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 DMA ringbuffer and descriptor allocation/management
6
7 Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
8
9 Some code in this file is derived from the b44.c driver
10 Copyright (C) 2002 David S. Miller
11 Copyright (C) Pekka Pietikainen
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; see the file COPYING. If not, write to
25 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
26 Boston, MA 02110-1301, USA.
27
28*/
29
30#include "bcm43xx.h"
31#include "bcm43xx_dma.h"
32#include "bcm43xx_main.h"
33#include "bcm43xx_debugfs.h"
34#include "bcm43xx_power.h"
35
36#include <linux/dmapool.h>
37#include <linux/pci.h>
38#include <linux/delay.h>
39#include <linux/skbuff.h>
40#include <asm/semaphore.h>
41
42
43static inline int free_slots(struct bcm43xx_dmaring *ring)
44{
45 return (ring->nr_slots - ring->used_slots);
46}
47
48static inline int next_slot(struct bcm43xx_dmaring *ring, int slot)
49{
50 assert(slot >= -1 && slot <= ring->nr_slots - 1);
51 if (slot == ring->nr_slots - 1)
52 return 0;
53 return slot + 1;
54}
55
56static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot)
57{
58 assert(slot >= 0 && slot <= ring->nr_slots - 1);
59 if (slot == 0)
60 return ring->nr_slots - 1;
61 return slot - 1;
62}
63
64/* Request a slot for usage. */
65static inline
66int request_slot(struct bcm43xx_dmaring *ring)
67{
68 int slot;
69
70 assert(ring->tx);
71 assert(!ring->suspended);
72 assert(free_slots(ring) != 0);
73
74 slot = next_slot(ring, ring->current_slot);
75 ring->current_slot = slot;
76 ring->used_slots++;
77
78 /* Check the number of available slots and suspend TX,
79 * if we are running low on free slots.
80 */
81 if (unlikely(free_slots(ring) < ring->suspend_mark)) {
82 netif_stop_queue(ring->bcm->net_dev);
83 ring->suspended = 1;
84 }
85#ifdef CONFIG_BCM43XX_DEBUG
86 if (ring->used_slots > ring->max_used_slots)
87 ring->max_used_slots = ring->used_slots;
88#endif /* CONFIG_BCM43XX_DEBUG*/
89
90 return slot;
91}
92
93/* Return a slot to the free slots. */
94static inline
95void return_slot(struct bcm43xx_dmaring *ring, int slot)
96{
97 assert(ring->tx);
98
99 ring->used_slots--;
100
101 /* Check if TX is suspended and check if we have
102 * enough free slots to resume it again.
103 */
104 if (unlikely(ring->suspended)) {
105 if (free_slots(ring) >= ring->resume_mark) {
106 ring->suspended = 0;
107 netif_wake_queue(ring->bcm->net_dev);
108 }
109 }
110}
111
112static inline
113dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
114 unsigned char *buf,
115 size_t len,
116 int tx)
117{
118 dma_addr_t dmaaddr;
119
120 if (tx) {
121 dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
122 buf, len,
123 DMA_TO_DEVICE);
124 } else {
125 dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
126 buf, len,
127 DMA_FROM_DEVICE);
128 }
129
130 return dmaaddr;
131}
132
133static inline
134void unmap_descbuffer(struct bcm43xx_dmaring *ring,
135 dma_addr_t addr,
136 size_t len,
137 int tx)
138{
139 if (tx) {
140 dma_unmap_single(&ring->bcm->pci_dev->dev,
141 addr, len,
142 DMA_TO_DEVICE);
143 } else {
144 dma_unmap_single(&ring->bcm->pci_dev->dev,
145 addr, len,
146 DMA_FROM_DEVICE);
147 }
148}
149
150static inline
151void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
152 dma_addr_t addr,
153 size_t len)
154{
155 assert(!ring->tx);
156
157 dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
158 addr, len, DMA_FROM_DEVICE);
159}
160
161static inline
162void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
163 dma_addr_t addr,
164 size_t len)
165{
166 assert(!ring->tx);
167
168 dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
169 addr, len, DMA_FROM_DEVICE);
170}
171
172static inline
173void mark_skb_mustfree(struct sk_buff *skb,
174 char mustfree)
175{
176 skb->cb[0] = mustfree;
177}
178
179static inline
180int skb_mustfree(struct sk_buff *skb)
181{
182 return (skb->cb[0] != 0);
183}
184
185/* Unmap and free a descriptor buffer. */
186static inline
187void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
188 struct bcm43xx_dmadesc *desc,
189 struct bcm43xx_dmadesc_meta *meta,
190 int irq_context)
191{
192 assert(meta->skb);
193 if (skb_mustfree(meta->skb)) {
194 if (irq_context)
195 dev_kfree_skb_irq(meta->skb);
196 else
197 dev_kfree_skb(meta->skb);
198 }
199 meta->skb = NULL;
200 if (meta->txb) {
201 ieee80211_txb_free(meta->txb);
202 meta->txb = NULL;
203 }
204}
205
206static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
207{
208 struct device *dev = &(ring->bcm->pci_dev->dev);
209
210 ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
211 &(ring->dmabase), GFP_KERNEL);
212 if (!ring->vbase) {
213 printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
214 return -ENOMEM;
215 }
216 if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
217 printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G\n");
218 dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
219 ring->vbase, ring->dmabase);
220 return -ENOMEM;
221 }
222 assert(!(ring->dmabase & 0x000003FF));
223 memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
224
225 return 0;
226}
227
228static void free_ringmemory(struct bcm43xx_dmaring *ring)
229{
230 struct device *dev = &(ring->bcm->pci_dev->dev);
231
232 dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
233 ring->vbase, ring->dmabase);
234}
235
236/* Reset the RX DMA channel */
237int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
238 u16 mmio_base)
239{
240 int i;
241 u32 value;
242
243 bcm43xx_write32(bcm,
244 mmio_base + BCM43xx_DMA_RX_CONTROL,
245 0x00000000);
246 for (i = 0; i < 1000; i++) {
247 value = bcm43xx_read32(bcm,
248 mmio_base + BCM43xx_DMA_RX_STATUS);
249 value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
250 if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
251 i = -1;
252 break;
253 }
254 udelay(10);
255 }
256 if (i != -1) {
257 printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n");
258 return -ENODEV;
259 }
260
261 return 0;
262}
263
264static inline int dmacontroller_rx_reset(struct bcm43xx_dmaring *ring)
265{
266 assert(!ring->tx);
267
268 return bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
269}
270
271/* Reset the RX DMA channel */
272int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
273 u16 mmio_base)
274{
275 int i;
276 u32 value;
277
278 for (i = 0; i < 1000; i++) {
279 value = bcm43xx_read32(bcm,
280 mmio_base + BCM43xx_DMA_TX_STATUS);
281 value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
282 if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
283 value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
284 value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
285 break;
286 udelay(10);
287 }
288 bcm43xx_write32(bcm,
289 mmio_base + BCM43xx_DMA_TX_CONTROL,
290 0x00000000);
291 for (i = 0; i < 1000; i++) {
292 value = bcm43xx_read32(bcm,
293 mmio_base + BCM43xx_DMA_TX_STATUS);
294 value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
295 if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
296 i = -1;
297 break;
298 }
299 udelay(10);
300 }
301 if (i != -1) {
302 printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n");
303 return -ENODEV;
304 }
305 /* ensure the reset is completed. */
306 udelay(300);
307
308 return 0;
309}
310
311static inline int dmacontroller_tx_reset(struct bcm43xx_dmaring *ring)
312{
313 assert(ring->tx);
314
315 return bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
316}
317
318static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
319 struct bcm43xx_dmadesc *desc,
320 struct bcm43xx_dmadesc_meta *meta,
321 gfp_t gfp_flags)
322{
323 struct bcm43xx_rxhdr *rxhdr;
324 dma_addr_t dmaaddr;
325 u32 desc_addr;
326 u32 desc_ctl;
327 const int slot = (int)(desc - ring->vbase);
328 struct sk_buff *skb;
329
330 assert(slot >= 0 && slot < ring->nr_slots);
331 assert(!ring->tx);
332
333 skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
334 if (unlikely(!skb))
335 return -ENOMEM;
336 dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
337 if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
338 unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
339 dev_kfree_skb_any(skb);
340 printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G\n");
341 return -ENOMEM;
342 }
343 meta->skb = skb;
344 meta->dmaaddr = dmaaddr;
345 skb->dev = ring->bcm->net_dev;
346 mark_skb_mustfree(skb, 1);
347 desc_addr = (u32)(dmaaddr + ring->memoffset);
348 desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
349 (u32)(ring->rx_buffersize - ring->frameoffset));
350 if (slot == ring->nr_slots - 1)
351 desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
352 set_desc_addr(desc, desc_addr);
353 set_desc_ctl(desc, desc_ctl);
354
355 rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
356 rxhdr->frame_length = 0;
357 rxhdr->flags1 = 0;
358
359 return 0;
360}
361
362/* Allocate the initial descbuffers.
363 * This is used for an RX ring only.
364 */
365static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
366{
367 int i, err = -ENOMEM;
368 struct bcm43xx_dmadesc *desc = NULL;
369 struct bcm43xx_dmadesc_meta *meta;
370
371 for (i = 0; i < ring->nr_slots; i++) {
372 desc = ring->vbase + i;
373 meta = ring->meta + i;
374
375 err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
376 if (err)
377 goto err_unwind;
378
379 assert(ring->used_slots <= ring->nr_slots);
380 }
381 ring->used_slots = ring->nr_slots;
382
383 err = 0;
384out:
385 return err;
386
387err_unwind:
388 for ( ; i >= 0; i--) {
389 desc = ring->vbase + i;
390 meta = ring->meta + i;
391
392 unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
393 dev_kfree_skb(meta->skb);
394 }
395 ring->used_slots = 0;
396 goto out;
397}
398
399/* Do initial setup of the DMA controller.
400 * Reset the controller, write the ring busaddress
401 * and switch the "enable" bit on.
402 */
403static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
404{
405 int err = 0;
406 u32 value;
407
408 if (ring->tx) {
409 /* Set Transmit Control register to "transmit enable" */
410 bcm43xx_write32(ring->bcm,
411 ring->mmio_base + BCM43xx_DMA_TX_CONTROL,
412 BCM43xx_DMA_TXCTRL_ENABLE);
413 /* Set Transmit Descriptor ring address. */
414 bcm43xx_write32(ring->bcm,
415 ring->mmio_base + BCM43xx_DMA_TX_DESC_RING,
416 ring->dmabase + ring->memoffset);
417 } else {
418 err = alloc_initial_descbuffers(ring);
419 if (err)
420 goto out;
421 /* Set Receive Control "receive enable" and frame offset */
422 value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
423 value |= BCM43xx_DMA_RXCTRL_ENABLE;
424 bcm43xx_write32(ring->bcm,
425 ring->mmio_base + BCM43xx_DMA_RX_CONTROL,
426 value);
427 /* Set Receive Descriptor ring address. */
428 bcm43xx_write32(ring->bcm,
429 ring->mmio_base + BCM43xx_DMA_RX_DESC_RING,
430 ring->dmabase + ring->memoffset);
431 /* Init the descriptor pointer. */
432 bcm43xx_write32(ring->bcm,
433 ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX,
434 200);
435 }
436
437out:
438 return err;
439}
440
441/* Shutdown the DMA controller. */
442static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
443{
444 if (ring->tx) {
445 dmacontroller_tx_reset(ring);
446 /* Zero out Transmit Descriptor ring address. */
447 bcm43xx_write32(ring->bcm,
448 ring->mmio_base + BCM43xx_DMA_TX_DESC_RING,
449 0x00000000);
450 } else {
451 dmacontroller_rx_reset(ring);
452 /* Zero out Receive Descriptor ring address. */
453 bcm43xx_write32(ring->bcm,
454 ring->mmio_base + BCM43xx_DMA_RX_DESC_RING,
455 0x00000000);
456 }
457}
458
459static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
460{
461 struct bcm43xx_dmadesc *desc;
462 struct bcm43xx_dmadesc_meta *meta;
463 int i;
464
465 if (!ring->used_slots)
466 return;
467 for (i = 0; i < ring->nr_slots; i++) {
468 desc = ring->vbase + i;
469 meta = ring->meta + i;
470
471 if (!meta->skb) {
472 assert(ring->tx);
473 assert(!meta->txb);
474 continue;
475 }
476 if (ring->tx) {
477 unmap_descbuffer(ring, meta->dmaaddr,
478 meta->skb->len, 1);
479 } else {
480 unmap_descbuffer(ring, meta->dmaaddr,
481 ring->rx_buffersize, 0);
482 }
483 free_descriptor_buffer(ring, desc, meta, 0);
484 }
485}
486
487/* Main initialization function. */
488static
489struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
490 u16 dma_controller_base,
491 int nr_descriptor_slots,
492 int tx)
493{
494 struct bcm43xx_dmaring *ring;
495 int err;
496
497 ring = kzalloc(sizeof(*ring), GFP_KERNEL);
498 if (!ring)
499 goto out;
500
501 ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
502 GFP_KERNEL);
503 if (!ring->meta)
504 goto err_kfree_ring;
505
506 ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
507#ifdef CONFIG_BCM947XX
508 if (bcm->pci_dev->bus->number == 0)
509 ring->memoffset = 0;
510#endif
511
512
513 spin_lock_init(&ring->lock);
514 ring->bcm = bcm;
515 ring->nr_slots = nr_descriptor_slots;
516 ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
517 ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
518 assert(ring->suspend_mark < ring->resume_mark);
519 ring->mmio_base = dma_controller_base;
520 if (tx) {
521 ring->tx = 1;
522 ring->current_slot = -1;
523 } else {
524 switch (dma_controller_base) {
525 case BCM43xx_MMIO_DMA1_BASE:
526 ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
527 ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
528 break;
529 case BCM43xx_MMIO_DMA4_BASE:
530 ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
531 ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
532 break;
533 default:
534 assert(0);
535 }
536 }
537
538 err = alloc_ringmemory(ring);
539 if (err)
540 goto err_kfree_meta;
541 err = dmacontroller_setup(ring);
542 if (err)
543 goto err_free_ringmemory;
544
545out:
546 return ring;
547
548err_free_ringmemory:
549 free_ringmemory(ring);
550err_kfree_meta:
551 kfree(ring->meta);
552err_kfree_ring:
553 kfree(ring);
554 ring = NULL;
555 goto out;
556}
557
558/* Main cleanup function. */
559static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
560{
561 if (!ring)
562 return;
563
564 dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
565 ring->mmio_base,
566 (ring->tx) ? "TX" : "RX",
567 ring->max_used_slots, ring->nr_slots);
568 /* Device IRQs are disabled prior entering this function,
569 * so no need to take care of concurrency with rx handler stuff.
570 */
571 dmacontroller_cleanup(ring);
572 free_all_descbuffers(ring);
573 free_ringmemory(ring);
574
575 kfree(ring->meta);
576 kfree(ring);
577}
578
579void bcm43xx_dma_free(struct bcm43xx_private *bcm)
580{
581 bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring1);
582 bcm->current_core->dma->rx_ring1 = NULL;
583 bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0);
584 bcm->current_core->dma->rx_ring0 = NULL;
585 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3);
586 bcm->current_core->dma->tx_ring3 = NULL;
587 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2);
588 bcm->current_core->dma->tx_ring2 = NULL;
589 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1);
590 bcm->current_core->dma->tx_ring1 = NULL;
591 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0);
592 bcm->current_core->dma->tx_ring0 = NULL;
593}
594
595int bcm43xx_dma_init(struct bcm43xx_private *bcm)
596{
597 struct bcm43xx_dmaring *ring;
598 int err = -ENOMEM;
599
600 /* setup TX DMA channels. */
601 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
602 BCM43xx_TXRING_SLOTS, 1);
603 if (!ring)
604 goto out;
605 bcm->current_core->dma->tx_ring0 = ring;
606
607 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
608 BCM43xx_TXRING_SLOTS, 1);
609 if (!ring)
610 goto err_destroy_tx0;
611 bcm->current_core->dma->tx_ring1 = ring;
612
613 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
614 BCM43xx_TXRING_SLOTS, 1);
615 if (!ring)
616 goto err_destroy_tx1;
617 bcm->current_core->dma->tx_ring2 = ring;
618
619 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
620 BCM43xx_TXRING_SLOTS, 1);
621 if (!ring)
622 goto err_destroy_tx2;
623 bcm->current_core->dma->tx_ring3 = ring;
624
625 /* setup RX DMA channels. */
626 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
627 BCM43xx_RXRING_SLOTS, 0);
628 if (!ring)
629 goto err_destroy_tx3;
630 bcm->current_core->dma->rx_ring0 = ring;
631
632 if (bcm->current_core->rev < 5) {
633 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
634 BCM43xx_RXRING_SLOTS, 0);
635 if (!ring)
636 goto err_destroy_rx0;
637 bcm->current_core->dma->rx_ring1 = ring;
638 }
639
640 dprintk(KERN_INFO PFX "DMA initialized\n");
641 err = 0;
642out:
643 return err;
644
645err_destroy_rx0:
646 bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0);
647 bcm->current_core->dma->rx_ring0 = NULL;
648err_destroy_tx3:
649 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3);
650 bcm->current_core->dma->tx_ring3 = NULL;
651err_destroy_tx2:
652 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2);
653 bcm->current_core->dma->tx_ring2 = NULL;
654err_destroy_tx1:
655 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1);
656 bcm->current_core->dma->tx_ring1 = NULL;
657err_destroy_tx0:
658 bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0);
659 bcm->current_core->dma->tx_ring0 = NULL;
660 goto out;
661}
662
663/* Generate a cookie for the TX header. */
664static inline
665u16 generate_cookie(struct bcm43xx_dmaring *ring,
666 int slot)
667{
668 u16 cookie = 0x0000;
669
670 /* Use the upper 4 bits of the cookie as
671 * DMA controller ID and store the slot number
672 * in the lower 12 bits
673 */
674 switch (ring->mmio_base) {
675 default:
676 assert(0);
677 case BCM43xx_MMIO_DMA1_BASE:
678 break;
679 case BCM43xx_MMIO_DMA2_BASE:
680 cookie = 0x1000;
681 break;
682 case BCM43xx_MMIO_DMA3_BASE:
683 cookie = 0x2000;
684 break;
685 case BCM43xx_MMIO_DMA4_BASE:
686 cookie = 0x3000;
687 break;
688 }
689 assert(((u16)slot & 0xF000) == 0x0000);
690 cookie |= (u16)slot;
691
692 return cookie;
693}
694
695/* Inspect a cookie and find out to which controller/slot it belongs. */
696static inline
697struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
698 u16 cookie, int *slot)
699{
700 struct bcm43xx_dmaring *ring = NULL;
701
702 switch (cookie & 0xF000) {
703 case 0x0000:
704 ring = bcm->current_core->dma->tx_ring0;
705 break;
706 case 0x1000:
707 ring = bcm->current_core->dma->tx_ring1;
708 break;
709 case 0x2000:
710 ring = bcm->current_core->dma->tx_ring2;
711 break;
712 case 0x3000:
713 ring = bcm->current_core->dma->tx_ring3;
714 break;
715 default:
716 assert(0);
717 }
718 *slot = (cookie & 0x0FFF);
719 assert(*slot >= 0 && *slot < ring->nr_slots);
720
721 return ring;
722}
723
724static inline void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
725 int slot)
726{
727 /* Everything is ready to start. Buffers are DMA mapped and
728 * associated with slots.
729 * "slot" is the last slot of the new frame we want to transmit.
730 * Close your seat belts now, please.
731 */
732 wmb();
733 slot = next_slot(ring, slot);
734 bcm43xx_write32(ring->bcm,
735 ring->mmio_base + BCM43xx_DMA_TX_DESC_INDEX,
736 (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
737}
738
739static inline
740int dma_tx_fragment(struct bcm43xx_dmaring *ring,
741 struct sk_buff *skb,
742 struct ieee80211_txb *txb,
743 u8 cur_frag)
744{
745 int slot;
746 struct bcm43xx_dmadesc *desc;
747 struct bcm43xx_dmadesc_meta *meta;
748 u32 desc_ctl;
749 u32 desc_addr;
750
751 assert(skb_shinfo(skb)->nr_frags == 0);
752
753 slot = request_slot(ring);
754 desc = ring->vbase + slot;
755 meta = ring->meta + slot;
756
757 if (cur_frag == 0) {
758 /* Save the txb pointer for freeing in xmitstatus IRQ */
759 meta->txb = txb;
760 }
761
762 /* Add a device specific TX header. */
763 assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
764 /* Reserve enough headroom for the device tx header. */
765 __skb_push(skb, sizeof(struct bcm43xx_txhdr));
766 /* Now calculate and add the tx header.
767 * The tx header includes the PLCP header.
768 */
769 bcm43xx_generate_txhdr(ring->bcm,
770 (struct bcm43xx_txhdr *)skb->data,
771 skb->data + sizeof(struct bcm43xx_txhdr),
772 skb->len - sizeof(struct bcm43xx_txhdr),
773 (cur_frag == 0),
774 generate_cookie(ring, slot));
775
776 meta->skb = skb;
777 meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
778 if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
779 return_slot(ring, slot);
780 printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G\n");
781 return -ENOMEM;
782 }
783
784 desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
785 desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
786 desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
787 desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
788 (u32)(meta->skb->len - ring->frameoffset));
789 if (slot == ring->nr_slots - 1)
790 desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
791
792 set_desc_ctl(desc, desc_ctl);
793 set_desc_addr(desc, desc_addr);
794 /* Now transfer the whole frame. */
795 dmacontroller_poke_tx(ring, slot);
796
797 return 0;
798}
799
800static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring,
801 struct ieee80211_txb *txb)
802{
803 /* We just received a packet from the kernel network subsystem.
804 * Add headers and DMA map the memory. Poke
805 * the device to send the stuff.
806 * Note that this is called from atomic context.
807 */
808 u8 i;
809 struct sk_buff *skb;
810
811 assert(ring->tx);
812 if (unlikely(free_slots(ring) < txb->nr_frags)) {
813 /* The queue should be stopped,
814 * if we are low on free slots.
815 * If this ever triggers, we have to lower the suspend_mark.
816 */
817 dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n");
818 return -ENOMEM;
819 }
820
821 assert(irqs_disabled());
822 spin_lock(&ring->lock);
823 for (i = 0; i < txb->nr_frags; i++) {
824 skb = txb->fragments[i];
825 /* We do not free the skb, as it is freed as
826 * part of the txb freeing.
827 */
828 mark_skb_mustfree(skb, 0);
829 dma_tx_fragment(ring, skb, txb, i);
830 //TODO: handle failure of dma_tx_fragment
831 }
832 spin_unlock(&ring->lock);
833
834 return 0;
835}
836
837int fastcall
838bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm,
839 struct ieee80211_txb *txb)
840{
841 return dma_transfer_txb(bcm->current_core->dma->tx_ring1,
842 txb);
843}
844
845void fastcall
846bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
847 struct bcm43xx_xmitstatus *status)
848{
849 struct bcm43xx_dmaring *ring;
850 struct bcm43xx_dmadesc *desc;
851 struct bcm43xx_dmadesc_meta *meta;
852 int is_last_fragment;
853 int slot;
854
855 ring = parse_cookie(bcm, status->cookie, &slot);
856 assert(ring);
857 assert(ring->tx);
858 assert(irqs_disabled());
859 spin_lock(&ring->lock);
860
861 assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
862 while (1) {
863 assert(slot >= 0 && slot < ring->nr_slots);
864 desc = ring->vbase + slot;
865 meta = ring->meta + slot;
866
867 is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
868 unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
869 free_descriptor_buffer(ring, desc, meta, 1);
870 /* Everything belonging to the slot is unmapped
871 * and freed, so we can return it.
872 */
873 return_slot(ring, slot);
874
875 if (is_last_fragment)
876 break;
877 slot = next_slot(ring, slot);
878 }
879 bcm->stats.last_tx = jiffies;
880
881 spin_unlock(&ring->lock);
882}
883
884static inline
885void dma_rx(struct bcm43xx_dmaring *ring,
886 int *slot)
887{
888 struct bcm43xx_dmadesc *desc;
889 struct bcm43xx_dmadesc_meta *meta;
890 struct bcm43xx_rxhdr *rxhdr;
891 struct sk_buff *skb;
892 u16 len;
893 int err;
894 dma_addr_t dmaaddr;
895
896 desc = ring->vbase + *slot;
897 meta = ring->meta + *slot;
898
899 sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
900 skb = meta->skb;
901
902 if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
903 /* We received an xmit status. */
904 struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
905 struct bcm43xx_xmitstatus stat;
906
907 stat.cookie = le16_to_cpu(hw->cookie);
908 stat.flags = hw->flags;
909 stat.cnt1 = hw->cnt1;
910 stat.cnt2 = hw->cnt2;
911 stat.seq = le16_to_cpu(hw->seq);
912 stat.unknown = le16_to_cpu(hw->unknown);
913
914 bcm43xx_debugfs_log_txstat(ring->bcm, &stat);
915 bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat);
916 /* recycle the descriptor buffer. */
917 sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize);
918
919 return;
920 }
921 rxhdr = (struct bcm43xx_rxhdr *)skb->data;
922 len = le16_to_cpu(rxhdr->frame_length);
923 if (len == 0) {
924 int i = 0;
925
926 do {
927 udelay(2);
928 barrier();
929 len = le16_to_cpu(rxhdr->frame_length);
930 } while (len == 0 && i++ < 5);
931 if (len == 0)
932 goto drop;
933 }
934 if (unlikely(len > ring->rx_buffersize)) {
935 /* The data did not fit into one descriptor buffer
936 * and is split over multiple buffers.
937 * This should never happen, as we try to allocate buffers
938 * big enough. So simply ignore this packet.
939 */
940 int cnt = 1;
941 s32 tmp = len - ring->rx_buffersize;
942
943 for ( ; tmp > 0; tmp -= ring->rx_buffersize) {
944 *slot = next_slot(ring, *slot);
945 cnt++;
946 }
947 printkl(KERN_ERR PFX "DMA RX buffer too small. %d dropped.\n",
948 cnt);
949 goto drop;
950 }
951 len -= IEEE80211_FCS_LEN;
952
953 dmaaddr = meta->dmaaddr;
954 err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
955 if (unlikely(err)) {
956 dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n");
957 goto drop;
958 }
959
960 unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
961 skb_put(skb, len + ring->frameoffset);
962 skb_pull(skb, ring->frameoffset);
963
964 err = bcm43xx_rx(ring->bcm, skb, rxhdr);
965 if (err) {
966 dev_kfree_skb_irq(skb);
967 goto drop;
968 }
969
970drop:
971 return;
972}
973
974void fastcall
975bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
976{
977 u32 status;
978 u16 descptr;
979 int slot, current_slot;
980#ifdef CONFIG_BCM43XX_DEBUG
981 int used_slots = 0;
982#endif
983
984 assert(!ring->tx);
985 assert(irqs_disabled());
986 spin_lock(&ring->lock);
987
988 status = bcm43xx_read32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_STATUS);
989 descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
990 current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
991 assert(current_slot >= 0 && current_slot < ring->nr_slots);
992
993 slot = ring->current_slot;
994 for ( ; slot != current_slot; slot = next_slot(ring, slot)) {
995 dma_rx(ring, &slot);
996#ifdef CONFIG_BCM43XX_DEBUG
997 if (++used_slots > ring->max_used_slots)
998 ring->max_used_slots = used_slots;
999#endif
1000 }
1001 bcm43xx_write32(ring->bcm,
1002 ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX,
1003 (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
1004 ring->current_slot = slot;
1005
1006 spin_unlock(&ring->lock);
1007}
1008
1009/* vim: set ts=8 sw=8 sts=8: */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
new file mode 100644
index 000000000000..e32cf68f8e1d
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
@@ -0,0 +1,176 @@
1#ifndef BCM43xx_DMA_H_
2#define BCM43xx_DMA_H_
3
4#include <linux/list.h>
5#include <linux/spinlock.h>
6#include <linux/workqueue.h>
7#include <linux/linkage.h>
8#include <asm/atomic.h>
9
10
11/* DMA-Interrupt reasons. */
12/*TODO: add the missing ones. */
13#define BCM43xx_DMAIRQ_ERR0 (1 << 10)
14#define BCM43xx_DMAIRQ_ERR1 (1 << 11)
15#define BCM43xx_DMAIRQ_ERR2 (1 << 12)
16#define BCM43xx_DMAIRQ_ERR3 (1 << 13)
17#define BCM43xx_DMAIRQ_ERR4 (1 << 14)
18#define BCM43xx_DMAIRQ_ERR5 (1 << 15)
19#define BCM43xx_DMAIRQ_RX_DONE (1 << 16)
20/* helpers */
21#define BCM43xx_DMAIRQ_ANYERR (BCM43xx_DMAIRQ_ERR0 | \
22 BCM43xx_DMAIRQ_ERR1 | \
23 BCM43xx_DMAIRQ_ERR2 | \
24 BCM43xx_DMAIRQ_ERR3 | \
25 BCM43xx_DMAIRQ_ERR4 | \
26 BCM43xx_DMAIRQ_ERR5)
27#define BCM43xx_DMAIRQ_FATALERR (BCM43xx_DMAIRQ_ERR0 | \
28 BCM43xx_DMAIRQ_ERR1 | \
29 BCM43xx_DMAIRQ_ERR2 | \
30 BCM43xx_DMAIRQ_ERR4 | \
31 BCM43xx_DMAIRQ_ERR5)
32#define BCM43xx_DMAIRQ_NONFATALERR BCM43xx_DMAIRQ_ERR3
33
34/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
35#define BCM43xx_DMA_TX_CONTROL 0x00
36#define BCM43xx_DMA_TX_DESC_RING 0x04
37#define BCM43xx_DMA_TX_DESC_INDEX 0x08
38#define BCM43xx_DMA_TX_STATUS 0x0c
39#define BCM43xx_DMA_RX_CONTROL 0x10
40#define BCM43xx_DMA_RX_DESC_RING 0x14
41#define BCM43xx_DMA_RX_DESC_INDEX 0x18
42#define BCM43xx_DMA_RX_STATUS 0x1c
43
44/* DMA controller channel control word values. */
45#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0)
46#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1)
47#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2)
48#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4)
49#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0)
50#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe
51#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1
52#define BCM43xx_DMA_RXCTRL_PIO (1 << 8)
53/* DMA controller channel status word values. */
54#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff
55#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000
56#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000
57#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000
58#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000
59#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000
60#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000
61#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000
62#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20)
63#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff
64#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000
65#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000
66#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000
67#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000
68#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000
69#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000
70#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000
71
72/* DMA descriptor control field values. */
73#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff
74#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */
75#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */
76#define BCM43xx_DMADTOR_FRAMEEND (1 << 30)
77#define BCM43xx_DMADTOR_FRAMESTART (1 << 31)
78
79/* Misc DMA constants */
80#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE
81#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF
82#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30)
83#define BCM43xx_DMA1_RX_FRAMEOFFSET 30
84#define BCM43xx_DMA4_RX_FRAMEOFFSET 0
85
86/* DMA engine tuning knobs */
87#define BCM43xx_TXRING_SLOTS 512
88#define BCM43xx_RXRING_SLOTS 64
89#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100)
90#define BCM43xx_DMA4_RXBUFFERSIZE 16
91/* Suspend the tx queue, if less than this percent slots are free. */
92#define BCM43xx_TXSUSPEND_PERCENT 20
93/* Resume the tx queue, if more than this percent slots are free. */
94#define BCM43xx_TXRESUME_PERCENT 50
95
96
97struct sk_buff;
98struct bcm43xx_private;
99struct bcm43xx_xmitstatus;
100
101
102struct bcm43xx_dmadesc {
103 __le32 _control;
104 __le32 _address;
105} __attribute__((__packed__));
106
107/* Macros to access the bcm43xx_dmadesc struct */
108#define get_desc_ctl(desc) le32_to_cpu((desc)->_control)
109#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0)
110#define get_desc_addr(desc) le32_to_cpu((desc)->_address)
111#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0)
112
113struct bcm43xx_dmadesc_meta {
114 /* The kernel DMA-able buffer. */
115 struct sk_buff *skb;
116 /* DMA base bus-address of the descriptor buffer. */
117 dma_addr_t dmaaddr;
118 /* Pointer to our txb (can be NULL).
119 * This should be freed in completion IRQ.
120 */
121 struct ieee80211_txb *txb;
122};
123
124struct bcm43xx_dmaring {
125 spinlock_t lock;
126 struct bcm43xx_private *bcm;
127 /* Kernel virtual base address of the ring memory. */
128 struct bcm43xx_dmadesc *vbase;
129 /* DMA memory offset */
130 dma_addr_t memoffset;
131 /* (Unadjusted) DMA base bus-address of the ring memory. */
132 dma_addr_t dmabase;
133 /* Meta data about all descriptors. */
134 struct bcm43xx_dmadesc_meta *meta;
135 /* Number of descriptor slots in the ring. */
136 int nr_slots;
137 /* Number of used descriptor slots. */
138 int used_slots;
139 /* Currently used slot in the ring. */
140 int current_slot;
141 /* Marks to suspend/resume the queue. */
142 int suspend_mark;
143 int resume_mark;
144 /* Frameoffset in octets. */
145 u32 frameoffset;
146 /* Descriptor buffer size. */
147 u16 rx_buffersize;
148 /* The MMIO base register of the DMA controller, this
149 * ring is posted to.
150 */
151 u16 mmio_base;
152 u8 tx:1, /* TRUE, if this is a TX ring. */
153 suspended:1; /* TRUE, if transfers are suspended on this ring. */
154#ifdef CONFIG_BCM43XX_DEBUG
155 /* Maximum number of used slots. */
156 int max_used_slots;
157#endif /* CONFIG_BCM43XX_DEBUG*/
158};
159
160
161int bcm43xx_dma_init(struct bcm43xx_private *bcm);
162void bcm43xx_dma_free(struct bcm43xx_private *bcm);
163
164int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
165 u16 dmacontroller_mmio_base);
166int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
167 u16 dmacontroller_mmio_base);
168
169int FASTCALL(bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm,
170 struct ieee80211_txb *txb));
171void FASTCALL(bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
172 struct bcm43xx_xmitstatus *status));
173
174void FASTCALL(bcm43xx_dma_rx(struct bcm43xx_dmaring *ring));
175
176#endif /* BCM43xx_DMA_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
new file mode 100644
index 000000000000..22587e0e1a05
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
@@ -0,0 +1,367 @@
1/*
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 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; see the file COPYING. If not, write to
23 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
24 Boston, MA 02110-1301, USA.
25
26*/
27
28#include "bcm43xx.h"
29#include "bcm43xx_ilt.h"
30#include "bcm43xx_phy.h"
31
32
33/**** Initial Internal Lookup Tables ****/
34
35const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = {
36 0xFEB93FFD, 0xFEC63FFD, /* 0 */
37 0xFED23FFD, 0xFEDF3FFD,
38 0xFEEC3FFE, 0xFEF83FFE,
39 0xFF053FFE, 0xFF113FFE,
40 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
41 0xFF373FFF, 0xFF443FFF,
42 0xFF503FFF, 0xFF5D3FFF,
43 0xFF693FFF, 0xFF763FFF,
44 0xFF824000, 0xFF8F4000, /* 16 */
45 0xFF9B4000, 0xFFA84000,
46 0xFFB54000, 0xFFC14000,
47 0xFFCE4000, 0xFFDA4000,
48 0xFFE74000, 0xFFF34000, /* 24 */
49 0x00004000, 0x000D4000,
50 0x00194000, 0x00264000,
51 0x00324000, 0x003F4000,
52 0x004B4000, 0x00584000, /* 32 */
53 0x00654000, 0x00714000,
54 0x007E4000, 0x008A3FFF,
55 0x00973FFF, 0x00A33FFF,
56 0x00B03FFF, 0x00BC3FFF, /* 40 */
57 0x00C93FFF, 0x00D63FFF,
58 0x00E23FFE, 0x00EF3FFE,
59 0x00FB3FFE, 0x01083FFE,
60 0x01143FFE, 0x01213FFD, /* 48 */
61 0x012E3FFD, 0x013A3FFD,
62 0x01473FFD,
63};
64
65const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = {
66 0xDB93CB87, 0xD666CF64, /* 0 */
67 0xD1FDD358, 0xCDA6D826,
68 0xCA38DD9F, 0xC729E2B4,
69 0xC469E88E, 0xC26AEE2B,
70 0xC0DEF46C, 0xC073FA62, /* 8 */
71 0xC01D00D5, 0xC0760743,
72 0xC1560D1E, 0xC2E51369,
73 0xC4ED18FF, 0xC7AC1ED7,
74 0xCB2823B2, 0xCEFA28D9, /* 16 */
75 0xD2F62D3F, 0xD7BB3197,
76 0xDCE53568, 0xE1FE3875,
77 0xE7D13B35, 0xED663D35,
78 0xF39B3EC4, 0xF98E3FA7, /* 24 */
79 0x00004000, 0x06723FA7,
80 0x0C653EC4, 0x129A3D35,
81 0x182F3B35, 0x1E023875,
82 0x231B3568, 0x28453197, /* 32 */
83 0x2D0A2D3F, 0x310628D9,
84 0x34D823B2, 0x38541ED7,
85 0x3B1318FF, 0x3D1B1369,
86 0x3EAA0D1E, 0x3F8A0743, /* 40 */
87 0x3FE300D5, 0x3F8DFA62,
88 0x3F22F46C, 0x3D96EE2B,
89 0x3B97E88E, 0x38D7E2B4,
90 0x35C8DD9F, 0x325AD826, /* 48 */
91 0x2E03D358, 0x299ACF64,
92 0x246DCB87,
93};
94
95const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = {
96 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
97 0x0202, 0x0282, 0x0302, 0x0382,
98 0x0402, 0x0482, 0x0502, 0x0582,
99 0x05E2, 0x0662, 0x06E2, 0x0762,
100 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
101 0x09C2, 0x0A22, 0x0AA2, 0x0B02,
102 0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
103 0x0D42, 0x0DA2, 0x0E02, 0x0E62,
104 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
105 0x1062, 0x10C2, 0x1122, 0x1182,
106 0x11E2, 0x1242, 0x12A2, 0x12E2,
107 0x1342, 0x13A2, 0x1402, 0x1442,
108 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
109 0x15E2, 0x1622, 0x1662, 0x16C1,
110 0x1701, 0x1741, 0x1781, 0x17E1,
111 0x1821, 0x1861, 0x18A1, 0x18E1,
112 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
113 0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
114 0x1B01, 0x1B41, 0x1B81, 0x1BA1,
115 0x1BE1, 0x1C21, 0x1C41, 0x1C81,
116 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
117 0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
118 0x1E21, 0x1E61, 0x1E81, 0x1EA1,
119 0x1EE1, 0x1F01, 0x1F21, 0x1F41,
120 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
121 0x2001, 0x2041, 0x2061, 0x2081,
122 0x20A1, 0x20C1, 0x20E1, 0x2101,
123 0x2121, 0x2141, 0x2161, 0x2181,
124 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
125 0x2221, 0x2241, 0x2261, 0x2281,
126 0x22A1, 0x22C1, 0x22C1, 0x22E1,
127 0x2301, 0x2321, 0x2341, 0x2361,
128 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
129 0x23E1, 0x23E1, 0x2401, 0x2421,
130 0x2441, 0x2441, 0x2461, 0x2481,
131 0x2481, 0x24A1, 0x24C1, 0x24C1,
132 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
133 0x2541, 0x2541, 0x2561, 0x2561,
134 0x2581, 0x25A1, 0x25A1, 0x25C1,
135 0x25C1, 0x25E1, 0x2601, 0x2601,
136 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
137 0x2661, 0x2661, 0x2681, 0x2681,
138 0x26A1, 0x26A1, 0x26C1, 0x26C1,
139 0x26E1, 0x26E1, 0x2701, 0x2701,
140 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
141 0x2760, 0x2760, 0x2780, 0x2780,
142 0x2780, 0x27A0, 0x27A0, 0x27C0,
143 0x27C0, 0x27E0, 0x27E0, 0x27E0,
144 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
145 0x2820, 0x2840, 0x2840, 0x2840,
146 0x2860, 0x2860, 0x2880, 0x2880,
147 0x2880, 0x28A0, 0x28A0, 0x28A0,
148 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
149 0x28E0, 0x28E0, 0x2900, 0x2900,
150 0x2900, 0x2920, 0x2920, 0x2920,
151 0x2940, 0x2940, 0x2940, 0x2960,
152 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
153 0x2980, 0x2980, 0x29A0, 0x29A0,
154 0x29A0, 0x29A0, 0x29C0, 0x29C0,
155 0x29C0, 0x29E0, 0x29E0, 0x29E0,
156 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
157 0x2A00, 0x2A20, 0x2A20, 0x2A20,
158 0x2A20, 0x2A40, 0x2A40, 0x2A40,
159 0x2A40, 0x2A60, 0x2A60, 0x2A60,
160};
161
162const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = {
163 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
164 0x05A9, 0x0669, 0x0709, 0x0789,
165 0x0829, 0x08A9, 0x0929, 0x0989,
166 0x0A09, 0x0A69, 0x0AC9, 0x0B29,
167 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
168 0x0D09, 0x0D69, 0x0DA9, 0x0E09,
169 0x0E69, 0x0EA9, 0x0F09, 0x0F49,
170 0x0FA9, 0x0FE9, 0x1029, 0x1089,
171 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
172 0x11E9, 0x1229, 0x1289, 0x12C9,
173 0x1309, 0x1349, 0x1389, 0x13C9,
174 0x1409, 0x1449, 0x14A9, 0x14E9,
175 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
176 0x1629, 0x1669, 0x16A9, 0x16E8,
177 0x1728, 0x1768, 0x17A8, 0x17E8,
178 0x1828, 0x1868, 0x18A8, 0x18E8,
179 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
180 0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
181 0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
182 0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
183 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
184 0x1E48, 0x1E88, 0x1EC8, 0x1F08,
185 0x1F48, 0x1F88, 0x1FE8, 0x2028,
186 0x2068, 0x20A8, 0x2108, 0x2148,
187 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
188 0x22C8, 0x2308, 0x2348, 0x23A8,
189 0x23E8, 0x2448, 0x24A8, 0x24E8,
190 0x2548, 0x25A8, 0x2608, 0x2668,
191 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
192 0x2847, 0x28C7, 0x2947, 0x29A7,
193 0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
194 0x2CA7, 0x2D67, 0x2E47, 0x2F67,
195 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
196 0x3806, 0x38A6, 0x3946, 0x39E6,
197 0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
198 0x3C45, 0x3CA5, 0x3D05, 0x3D85,
199 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
200 0x3F45, 0x3FA5, 0x4005, 0x4045,
201 0x40A5, 0x40E5, 0x4145, 0x4185,
202 0x41E5, 0x4225, 0x4265, 0x42C5,
203 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
204 0x4424, 0x4464, 0x44C4, 0x4504,
205 0x4544, 0x4584, 0x45C4, 0x4604,
206 0x4644, 0x46A4, 0x46E4, 0x4724,
207 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
208 0x4864, 0x48A4, 0x48E4, 0x4924,
209 0x4964, 0x49A4, 0x49E4, 0x4A24,
210 0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
211 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
212 0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
213 0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
214 0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
215 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
216 0x5083, 0x50C3, 0x5103, 0x5143,
217 0x5183, 0x51E2, 0x5222, 0x5262,
218 0x52A2, 0x52E2, 0x5342, 0x5382,
219 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
220 0x5502, 0x5542, 0x55A2, 0x55E2,
221 0x5642, 0x5682, 0x56E2, 0x5722,
222 0x5782, 0x57E1, 0x5841, 0x58A1,
223 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
224 0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
225 0x5C61, 0x5D01, 0x5D80, 0x5E20,
226 0x5EE0, 0x5FA0, 0x6080, 0x61C0,
227};
228
229const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = {
230 0x0001, 0x0001, 0x0001, 0xFFFE,
231 0xFFFE, 0x3FFF, 0x1000, 0x0393,
232};
233
234const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = {
235 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
236 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
237};
238
239const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = {
240 0x013C, 0x01F5, 0x031A, 0x0631,
241 0x0001, 0x0001, 0x0001, 0x0001,
242};
243
244const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = {
245 0x5484, 0x3C40, 0x0000, 0x0000,
246 0x0000, 0x0000, 0x0000, 0x0000,
247};
248
249const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = {
250 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
251 0x2F2D, 0x2A2A, 0x2527, 0x1F21,
252 0x1A1D, 0x1719, 0x1616, 0x1414,
253 0x1414, 0x1400, 0x1414, 0x1614,
254 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
255 0x2A27, 0x2F2A, 0x332D, 0x3B35,
256 0x5140, 0x6C62, 0x0077,
257};
258
259const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = {
260 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
261 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
262 0x969B, 0x9195, 0x8F8F, 0x8A8A,
263 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
264 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
265 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
266 0xCBC0, 0xD8D4, 0x00DD,
267};
268
269const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = {
270 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
271 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
272 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
273 0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
274 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
275 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
276 0xA4A4, 0xA4A4, 0x00A4,
277};
278
279const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = {
280 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
281 0x0067, 0x0063, 0x005E, 0x0059,
282 0x0054, 0x0050, 0x004B, 0x0046,
283 0x0042, 0x003D, 0x003D, 0x003D,
284 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
285 0x003D, 0x003D, 0x003D, 0x003D,
286 0x003D, 0x003D, 0x0000, 0x003D,
287 0x003D, 0x003D, 0x003D, 0x003D,
288 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
289 0x003D, 0x003D, 0x003D, 0x003D,
290 0x0042, 0x0046, 0x004B, 0x0050,
291 0x0054, 0x0059, 0x005E, 0x0063,
292 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
293 0x007A,
294};
295
296const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = {
297 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
298 0x00D6, 0x00D4, 0x00D2, 0x00CF,
299 0x00CD, 0x00CA, 0x00C7, 0x00C4,
300 0x00C1, 0x00BE, 0x00BE, 0x00BE,
301 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
302 0x00BE, 0x00BE, 0x00BE, 0x00BE,
303 0x00BE, 0x00BE, 0x0000, 0x00BE,
304 0x00BE, 0x00BE, 0x00BE, 0x00BE,
305 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
306 0x00BE, 0x00BE, 0x00BE, 0x00BE,
307 0x00C1, 0x00C4, 0x00C7, 0x00CA,
308 0x00CD, 0x00CF, 0x00D2, 0x00D4,
309 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
310 0x00DE,
311};
312
313/**** Helper functions to access the device Internal Lookup Tables ****/
314
315void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val)
316{
317 if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) {
318 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
319 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val);
320 } else {
321 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
322 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val);
323 }
324}
325
326u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset)
327{
328 if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) {
329 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
330 return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1);
331 } else {
332 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
333 return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1);
334 }
335}
336
337void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val)
338{
339 if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) {
340 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
341 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (u16)(val >> 16));
342 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, (u16)(val & 0x0000FFFF));
343 } else {
344 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
345 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (u16)(val >> 16));
346 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, (u16)(val & 0x0000FFFF));
347 }
348}
349
350u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset)
351{
352 u32 ret;
353
354 if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) {
355 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
356 ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA2);
357 ret <<= 16;
358 ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1);
359 } else {
360 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
361 ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA2);
362 ret <<= 16;
363 ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1);
364 }
365
366 return ret;
367}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
new file mode 100644
index 000000000000..d92527fd83e9
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
@@ -0,0 +1,34 @@
1#ifndef BCM43xx_ILT_H_
2#define BCM43xx_ILT_H_
3
4#define BCM43xx_ILT_ROTOR_SIZE 53
5extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE];
6#define BCM43xx_ILT_RETARD_SIZE 53
7extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE];
8#define BCM43xx_ILT_FINEFREQA_SIZE 256
9extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE];
10#define BCM43xx_ILT_FINEFREQG_SIZE 256
11extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE];
12#define BCM43xx_ILT_NOISEA2_SIZE 8
13extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE];
14#define BCM43xx_ILT_NOISEA3_SIZE 8
15extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE];
16#define BCM43xx_ILT_NOISEG1_SIZE 8
17extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE];
18#define BCM43xx_ILT_NOISEG2_SIZE 8
19extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE];
20#define BCM43xx_ILT_NOISESCALEG_SIZE 27
21extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE];
22extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE];
23extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE];
24#define BCM43xx_ILT_SIGMASQR_SIZE 53
25extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE];
26extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE];
27
28
29void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val);
30u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset);
31void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val);
32u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset);
33
34#endif /* BCM43xx_ILT_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
new file mode 100644
index 000000000000..455a0c743f73
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -0,0 +1,261 @@
1/*
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 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; see the file COPYING. If not, write to
23 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
24 Boston, MA 02110-1301, USA.
25
26*/
27
28#include "bcm43xx_leds.h"
29#include "bcm43xx.h"
30
31#include <asm/bitops.h>
32
33
34static void bcm43xx_led_changestate(struct bcm43xx_led *led)
35{
36 struct bcm43xx_private *bcm = led->bcm;
37 const int index = bcm43xx_led_index(led);
38 u16 ledctl;
39
40 assert(index >= 0 && index < BCM43xx_NR_LEDS);
41 assert(led->blink_interval);
42 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
43 __change_bit(index, (unsigned long *)(&ledctl));
44 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
45}
46
47static void bcm43xx_led_blink(unsigned long d)
48{
49 struct bcm43xx_led *led = (struct bcm43xx_led *)d;
50 struct bcm43xx_private *bcm = led->bcm;
51 unsigned long flags;
52
53 spin_lock_irqsave(&bcm->lock, flags);
54 if (led->blink_interval) {
55 bcm43xx_led_changestate(led);
56 mod_timer(&led->blink_timer, jiffies + led->blink_interval);
57 }
58 spin_unlock_irqrestore(&bcm->lock, flags);
59}
60
61static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
62 unsigned long interval)
63{
64 led->blink_interval = interval;
65 bcm43xx_led_changestate(led);
66 led->blink_timer.expires = jiffies + interval;
67 add_timer(&led->blink_timer);
68}
69
70static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
71{
72 struct bcm43xx_private *bcm = led->bcm;
73 const int index = bcm43xx_led_index(led);
74 u16 ledctl;
75
76 if (!led->blink_interval)
77 return;
78 if (unlikely(sync))
79 del_timer_sync(&led->blink_timer);
80 else
81 del_timer(&led->blink_timer);
82 led->blink_interval = 0;
83
84 /* Make sure the LED is turned off. */
85 assert(index >= 0 && index < BCM43xx_NR_LEDS);
86 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
87 if (led->activelow)
88 ledctl |= (1 << index);
89 else
90 ledctl &= ~(1 << index);
91 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
92}
93
94int bcm43xx_leds_init(struct bcm43xx_private *bcm)
95{
96 struct bcm43xx_led *led;
97 u8 sprom[4];
98 int i;
99
100 sprom[0] = bcm->sprom.wl0gpio0;
101 sprom[1] = bcm->sprom.wl0gpio1;
102 sprom[2] = bcm->sprom.wl0gpio2;
103 sprom[3] = bcm->sprom.wl0gpio3;
104
105 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
106 led = &(bcm->leds[i]);
107 led->bcm = bcm;
108 init_timer(&led->blink_timer);
109 led->blink_timer.data = (unsigned long)led;
110 led->blink_timer.function = bcm43xx_led_blink;
111
112 if (sprom[i] == 0xFF) {
113 /* SPROM information not set. */
114 switch (i) {
115 case 0:
116 if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
117 led->behaviour = BCM43xx_LED_RADIO_ALL;
118 else
119 led->behaviour = BCM43xx_LED_ACTIVITY;
120 break;
121 case 1:
122 led->behaviour = BCM43xx_LED_RADIO_B;
123 break;
124 case 2:
125 led->behaviour = BCM43xx_LED_RADIO_A;
126 break;
127 case 3:
128 led->behaviour = BCM43xx_LED_OFF;
129 break;
130 default:
131 assert(0);
132 }
133 } else {
134 led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
135 led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
136 }
137 }
138
139 return 0;
140}
141
142void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
143{
144 struct bcm43xx_led *led;
145 int i;
146
147 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
148 led = &(bcm->leds[i]);
149 bcm43xx_led_blink_stop(led, 1);
150 }
151 bcm43xx_leds_turn_off(bcm);
152}
153
154void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
155{
156 struct bcm43xx_led *led;
157 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
158 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
159 const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
160 int i, turn_on = 0;
161 unsigned long interval = 0;
162 u16 ledctl;
163
164 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
165 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
166 led = &(bcm->leds[i]);
167 if (led->behaviour == BCM43xx_LED_INACTIVE)
168 continue;
169
170 switch (led->behaviour) {
171 case BCM43xx_LED_OFF:
172 turn_on = 0;
173 break;
174 case BCM43xx_LED_ON:
175 turn_on = 1;
176 break;
177 case BCM43xx_LED_ACTIVITY:
178 turn_on = activity;
179 break;
180 case BCM43xx_LED_RADIO_ALL:
181 turn_on = radio->enabled;
182 break;
183 case BCM43xx_LED_RADIO_A:
184 turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
185 break;
186 case BCM43xx_LED_RADIO_B:
187 turn_on = (radio->enabled &&
188 (phy->type == BCM43xx_PHYTYPE_B ||
189 phy->type == BCM43xx_PHYTYPE_G));
190 break;
191 case BCM43xx_LED_MODE_BG:
192 turn_on = 0;
193 if (phy->type == BCM43xx_PHYTYPE_G &&
194 1/*FIXME: using G rates.*/)
195 turn_on = 1;
196 break;
197 case BCM43xx_LED_TRANSFER:
198 if (transferring)
199 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
200 else
201 bcm43xx_led_blink_stop(led, 0);
202 continue;
203 case BCM43xx_LED_APTRANSFER:
204 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
205 if (transferring) {
206 interval = BCM43xx_LEDBLINK_FAST;
207 turn_on = 1;
208 }
209 } else {
210 turn_on = 1;
211 if (0/*TODO: not assoc*/)
212 interval = BCM43xx_LEDBLINK_SLOW;
213 else if (transferring)
214 interval = BCM43xx_LEDBLINK_FAST;
215 else
216 turn_on = 0;
217 }
218 if (turn_on)
219 bcm43xx_led_blink_start(led, interval);
220 else
221 bcm43xx_led_blink_stop(led, 0);
222 continue;
223 case BCM43xx_LED_WEIRD:
224 //TODO
225 turn_on = 0;
226 break;
227 case BCM43xx_LED_ASSOC:
228 if (1/*TODO: associated*/)
229 turn_on = 1;
230 break;
231 default:
232 assert(0);
233 };
234
235 if (led->activelow)
236 turn_on = !turn_on;
237 if (turn_on)
238 ledctl |= (1 << i);
239 else
240 ledctl &= ~(1 << i);
241 }
242 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
243}
244
245void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm)
246{
247 struct bcm43xx_led *led;
248 u16 ledctl = 0;
249 int i;
250
251 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
252 led = &(bcm->leds[i]);
253 if (led->behaviour == BCM43xx_LED_INACTIVE)
254 continue;
255 if (led->activelow)
256 ledctl |= (1 << i);
257 }
258 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
259}
260
261/* vim: set ts=8 sw=8 sts=8: */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
new file mode 100644
index 000000000000..489a2b1e9068
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
@@ -0,0 +1,47 @@
1#ifndef BCM43xx_LEDS_H_
2#define BCM43xx_LEDS_H_
3
4#include <linux/types.h>
5#include <linux/timer.h>
6
7
8struct bcm43xx_led {
9 u8 behaviour:7;
10 u8 activelow:1;
11
12 struct bcm43xx_private *bcm;
13 struct timer_list blink_timer;
14 unsigned long blink_interval;
15};
16#define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds))
17
18/* Delay between state changes when blinking in jiffies */
19#define BCM43xx_LEDBLINK_SLOW (HZ / 2)
20#define BCM43xx_LEDBLINK_MEDIUM (HZ / 4)
21#define BCM43xx_LEDBLINK_FAST (HZ / 8)
22
23#define BCM43xx_LED_XFER_THRES (HZ / 100)
24
25#define BCM43xx_LED_BEHAVIOUR 0x7F
26#define BCM43xx_LED_ACTIVELOW 0x80
27enum { /* LED behaviour values */
28 BCM43xx_LED_OFF,
29 BCM43xx_LED_ON,
30 BCM43xx_LED_ACTIVITY,
31 BCM43xx_LED_RADIO_ALL,
32 BCM43xx_LED_RADIO_A,
33 BCM43xx_LED_RADIO_B,
34 BCM43xx_LED_MODE_BG,
35 BCM43xx_LED_TRANSFER,
36 BCM43xx_LED_APTRANSFER,
37 BCM43xx_LED_WEIRD,//FIXME
38 BCM43xx_LED_ASSOC,
39 BCM43xx_LED_INACTIVE,
40};
41
42int bcm43xx_leds_init(struct bcm43xx_private *bcm);
43void bcm43xx_leds_exit(struct bcm43xx_private *bcm);
44void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity);
45void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm);
46
47#endif /* BCM43xx_LEDS_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
new file mode 100644
index 000000000000..be60a6509f20
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -0,0 +1,4597 @@
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mbuesch@freenet.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11 Some parts of the code in this file are derived from the ipw2200
12 driver Copyright(c) 2003 - 2004 Intel Corporation.
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
27 Boston, MA 02110-1301, USA.
28
29*/
30
31#include <linux/delay.h>
32#include <linux/init.h>
33#include <linux/moduleparam.h>
34#include <linux/if_arp.h>
35#include <linux/etherdevice.h>
36#include <linux/version.h>
37#include <linux/firmware.h>
38#include <linux/wireless.h>
39#include <linux/workqueue.h>
40#include <linux/skbuff.h>
41#include <net/iw_handler.h>
42
43#include "bcm43xx.h"
44#include "bcm43xx_main.h"
45#include "bcm43xx_debugfs.h"
46#include "bcm43xx_radio.h"
47#include "bcm43xx_phy.h"
48#include "bcm43xx_dma.h"
49#include "bcm43xx_pio.h"
50#include "bcm43xx_power.h"
51#include "bcm43xx_wx.h"
52
53
54MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
55MODULE_AUTHOR("Martin Langer");
56MODULE_AUTHOR("Stefano Brivio");
57MODULE_AUTHOR("Michael Buesch");
58MODULE_LICENSE("GPL");
59
60#ifdef CONFIG_BCM947XX
61extern char *nvram_get(char *name);
62#endif
63
64/* Module parameters */
65static int modparam_pio;
66module_param_named(pio, modparam_pio, int, 0444);
67MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
68
69static int modparam_bad_frames_preempt;
70module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
71MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
72
73static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
74module_param_named(short_retry, modparam_short_retry, int, 0444);
75MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
76
77static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
78module_param_named(long_retry, modparam_long_retry, int, 0444);
79MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
80
81static int modparam_locale = -1;
82module_param_named(locale, modparam_locale, int, 0444);
83MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
84
85static int modparam_outdoor;
86module_param_named(outdoor, modparam_outdoor, int, 0444);
87MODULE_PARM_DESC(outdoor, "Set to 1, if you are using the device outdoor, 0 otherwise.");
88
89static int modparam_noleds;
90module_param_named(noleds, modparam_noleds, int, 0444);
91MODULE_PARM_DESC(noleds, "Turn off all LED activity");
92
93#ifdef CONFIG_BCM43XX_DEBUG
94static char modparam_fwpostfix[64];
95module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
96MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
97#else
98# define modparam_fwpostfix ""
99#endif /* CONFIG_BCM43XX_DEBUG*/
100
101
102/* If you want to debug with just a single device, enable this,
103 * where the string is the pci device ID (as given by the kernel's
104 * pci_name function) of the device to be used.
105 */
106//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0"
107
108/* If you want to enable printing of each MMIO access, enable this. */
109//#define DEBUG_ENABLE_MMIO_PRINT
110
111/* If you want to enable printing of MMIO access within
112 * ucode/pcm upload, initvals write, enable this.
113 */
114//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
115
116/* If you want to enable printing of PCI Config Space access, enable this */
117//#define DEBUG_ENABLE_PCILOG
118
119
120static struct pci_device_id bcm43xx_pci_tbl[] = {
121
122 /* Detailed list maintained at:
123 * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
124 */
125
126#ifdef CONFIG_BCM947XX
127 /* SB bus on BCM947xx */
128 { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
129#endif
130
131 /* Broadcom 4303 802.11b */
132 { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
133
134 /* Broadcom 4307 802.11b */
135 { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
136
137 /* Broadcom 4318 802.11b/g */
138 { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
139
140 /* Broadcom 4306 802.11b/g */
141 { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
142
143 /* Broadcom 4306 802.11a */
144// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
145
146 /* Broadcom 4309 802.11a/b/g */
147 { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
148
149 /* Broadcom 43XG 802.11b/g */
150 { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
151
152 /* required last entry */
153 { 0, },
154};
155MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
156
157static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
158{
159 u32 status;
160
161 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
162 if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
163 val = swab32(val);
164
165 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
166 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
167}
168
169static inline
170void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
171 u16 routing, u16 offset)
172{
173 u32 control;
174
175 /* "offset" is the WORD offset. */
176
177 control = routing;
178 control <<= 16;
179 control |= offset;
180 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
181}
182
183u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
184 u16 routing, u16 offset)
185{
186 u32 ret;
187
188 if (routing == BCM43xx_SHM_SHARED) {
189 if (offset & 0x0003) {
190 /* Unaligned access */
191 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
192 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
193 ret <<= 16;
194 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
195 ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
196
197 return ret;
198 }
199 offset >>= 2;
200 }
201 bcm43xx_shm_control_word(bcm, routing, offset);
202 ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
203
204 return ret;
205}
206
207u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
208 u16 routing, u16 offset)
209{
210 u16 ret;
211
212 if (routing == BCM43xx_SHM_SHARED) {
213 if (offset & 0x0003) {
214 /* Unaligned access */
215 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
216 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
217
218 return ret;
219 }
220 offset >>= 2;
221 }
222 bcm43xx_shm_control_word(bcm, routing, offset);
223 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
224
225 return ret;
226}
227
228void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
229 u16 routing, u16 offset,
230 u32 value)
231{
232 if (routing == BCM43xx_SHM_SHARED) {
233 if (offset & 0x0003) {
234 /* Unaligned access */
235 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
236 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
237 (value >> 16) & 0xffff);
238 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
239 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);
246 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
247}
248
249void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
250 u16 routing, u16 offset,
251 u16 value)
252{
253 if (routing == BCM43xx_SHM_SHARED) {
254 if (offset & 0x0003) {
255 /* Unaligned access */
256 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
257 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
258 value);
259 return;
260 }
261 offset >>= 2;
262 }
263 bcm43xx_shm_control_word(bcm, routing, offset);
264 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);
265}
266
267void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf)
268{
269 /* We need to be careful. As we read the TSF from multiple
270 * registers, we should take care of register overflows.
271 * In theory, the whole tsf read process should be atomic.
272 * We try to be atomic here, by restaring the read process,
273 * if any of the high registers changed (overflew).
274 */
275 if (bcm->current_core->rev >= 3) {
276 u32 low, high, high2;
277
278 do {
279 high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
280 low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW);
281 high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH);
282 } while (unlikely(high != high2));
283
284 *tsf = high;
285 *tsf <<= 32;
286 *tsf |= low;
287 } else {
288 u64 tmp;
289 u16 v0, v1, v2, v3;
290 u16 test1, test2, test3;
291
292 do {
293 v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
294 v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
295 v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
296 v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0);
297
298 test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3);
299 test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2);
300 test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1);
301 } while (v3 != test3 || v2 != test2 || v1 != test1);
302
303 *tsf = v3;
304 *tsf <<= 48;
305 tmp = v2;
306 tmp <<= 32;
307 *tsf |= tmp;
308 tmp = v1;
309 tmp <<= 16;
310 *tsf |= tmp;
311 *tsf |= v0;
312 }
313}
314
315void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
316{
317 u32 status;
318
319 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
320 status |= BCM43xx_SBF_TIME_UPDATE;
321 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
322
323 /* Be careful with the in-progress timer.
324 * First zero out the low register, so we have a full
325 * register-overflow duration to complete the operation.
326 */
327 if (bcm->current_core->rev >= 3) {
328 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
329 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
330
331 barrier();
332 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
333 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
334 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
335 } else {
336 u16 v0 = (tsf & 0x000000000000FFFFULL);
337 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
338 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
339 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
340
341 barrier();
342 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
343 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
344 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
345 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
346 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
347 }
348
349 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
350 status &= ~BCM43xx_SBF_TIME_UPDATE;
351 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
352}
353
354static inline
355u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp,
356 const int ofdm_modulation)
357{
358 u8 rate;
359
360 if (ofdm_modulation) {
361 switch (plcp->raw[0] & 0xF) {
362 case 0xB:
363 rate = IEEE80211_OFDM_RATE_6MB;
364 break;
365 case 0xF:
366 rate = IEEE80211_OFDM_RATE_9MB;
367 break;
368 case 0xA:
369 rate = IEEE80211_OFDM_RATE_12MB;
370 break;
371 case 0xE:
372 rate = IEEE80211_OFDM_RATE_18MB;
373 break;
374 case 0x9:
375 rate = IEEE80211_OFDM_RATE_24MB;
376 break;
377 case 0xD:
378 rate = IEEE80211_OFDM_RATE_36MB;
379 break;
380 case 0x8:
381 rate = IEEE80211_OFDM_RATE_48MB;
382 break;
383 case 0xC:
384 rate = IEEE80211_OFDM_RATE_54MB;
385 break;
386 default:
387 rate = 0;
388 assert(0);
389 }
390 } else {
391 switch (plcp->raw[0]) {
392 case 0x0A:
393 rate = IEEE80211_CCK_RATE_1MB;
394 break;
395 case 0x14:
396 rate = IEEE80211_CCK_RATE_2MB;
397 break;
398 case 0x37:
399 rate = IEEE80211_CCK_RATE_5MB;
400 break;
401 case 0x6E:
402 rate = IEEE80211_CCK_RATE_11MB;
403 break;
404 default:
405 rate = 0;
406 assert(0);
407 }
408 }
409
410 return rate;
411}
412
413static inline
414u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
415{
416 switch (bitrate) {
417 case IEEE80211_CCK_RATE_1MB:
418 return 0x0A;
419 case IEEE80211_CCK_RATE_2MB:
420 return 0x14;
421 case IEEE80211_CCK_RATE_5MB:
422 return 0x37;
423 case IEEE80211_CCK_RATE_11MB:
424 return 0x6E;
425 }
426 assert(0);
427 return 0;
428}
429
430static inline
431u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
432{
433 switch (bitrate) {
434 case IEEE80211_OFDM_RATE_6MB:
435 return 0xB;
436 case IEEE80211_OFDM_RATE_9MB:
437 return 0xF;
438 case IEEE80211_OFDM_RATE_12MB:
439 return 0xA;
440 case IEEE80211_OFDM_RATE_18MB:
441 return 0xE;
442 case IEEE80211_OFDM_RATE_24MB:
443 return 0x9;
444 case IEEE80211_OFDM_RATE_36MB:
445 return 0xD;
446 case IEEE80211_OFDM_RATE_48MB:
447 return 0x8;
448 case IEEE80211_OFDM_RATE_54MB:
449 return 0xC;
450 }
451 assert(0);
452 return 0;
453}
454
455static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
456 u16 octets, const u8 bitrate,
457 const int ofdm_modulation)
458{
459 __le32 *data = &(plcp->data);
460 __u8 *raw = plcp->raw;
461
462 /* Account for hardware-appended FCS. */
463 octets += IEEE80211_FCS_LEN;
464
465 if (ofdm_modulation) {
466 *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
467 assert(!(octets & 0xF000));
468 *data |= (octets << 5);
469 *data = cpu_to_le32(*data);
470 } else {
471 u32 plen;
472
473 plen = octets * 16 / bitrate;
474 if ((octets * 16 % bitrate) > 0) {
475 plen++;
476 if ((bitrate == IEEE80211_CCK_RATE_11MB)
477 && ((octets * 8 % 11) < 4)) {
478 raw[1] = 0x84;
479 } else
480 raw[1] = 0x04;
481 } else
482 raw[1] = 0x04;
483 *data |= cpu_to_le32(plen << 16);
484 raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
485 }
486
487//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP");
488}
489
490void fastcall
491bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
492 struct bcm43xx_txhdr *txhdr,
493 const unsigned char *fragment_data,
494 unsigned int fragment_len,
495 const int is_first_fragment,
496 const u16 cookie)
497{
498 const struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
499 const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data;
500 const struct ieee80211_security *secinfo = &bcm->ieee->sec;
501 u8 bitrate;
502 int ofdm_modulation;
503 u8 fallback_bitrate;
504 int fallback_ofdm_modulation;
505 u16 tmp;
506 u16 encrypt_frame;
507
508 /* Now construct the TX header. */
509 memset(txhdr, 0, sizeof(*txhdr));
510
511 //TODO: Some RTS/CTS stuff has to be done.
512 //TODO: Encryption stuff.
513 //TODO: others?
514
515 bitrate = bcm->softmac->txrates.default_rate;
516 ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
517 fallback_bitrate = bcm->softmac->txrates.default_fallback;
518 fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
519
520 /* Set Frame Control from 80211 header. */
521 txhdr->frame_control = wireless_header->frame_ctl;
522 /* Copy address1 from 80211 header. */
523 memcpy(txhdr->mac1, wireless_header->addr1, 6);
524 /* Set the fallback duration ID. */
525 //FIXME: We use the original durid for now.
526 txhdr->fallback_dur_id = wireless_header->duration_id;
527
528 /* Set the cookie (used as driver internal ID for the frame) */
529 txhdr->cookie = cpu_to_le16(cookie);
530
531 encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
532 if (encrypt_frame && !bcm->ieee->host_encrypt) {
533 const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
534 if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) {
535 dprintkl(KERN_ERR PFX "invalid packet with PROTECTED"
536 "flag set discarded");
537 return;
538 }
539 memcpy(txhdr->wep_iv, hdr->payload, 4);
540 /* Hardware appends ICV. */
541 fragment_len += 4;
542 }
543
544 /* Generate the PLCP header and the fallback PLCP header. */
545 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
546 fragment_len,
547 bitrate, ofdm_modulation);
548 bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len,
549 fallback_bitrate, fallback_ofdm_modulation);
550
551 /* Set the CONTROL field */
552 tmp = 0;
553 if (ofdm_modulation)
554 tmp |= BCM43xx_TXHDRCTL_OFDM;
555 if (bcm->short_preamble) //FIXME: could be the other way around, please test
556 tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
557 tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
558 & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
559 txhdr->control = cpu_to_le16(tmp);
560
561 /* Set the FLAGS field */
562 tmp = 0;
563 if (!is_multicast_ether_addr(wireless_header->addr1) &&
564 !is_broadcast_ether_addr(wireless_header->addr1))
565 tmp |= BCM43xx_TXHDRFLAG_EXPECTACK;
566 if (1 /* FIXME: PS poll?? */)
567 tmp |= 0x10; // FIXME: unknown meaning.
568 if (fallback_ofdm_modulation)
569 tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
570 if (is_first_fragment)
571 tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
572 txhdr->flags = cpu_to_le16(tmp);
573
574 /* Set WSEC/RATE field */
575 if (encrypt_frame && !bcm->ieee->host_encrypt) {
576 tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
577 & BCM43xx_TXHDR_WSEC_ALGO_MASK;
578 tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
579 & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
580 txhdr->wsec_rate = cpu_to_le16(tmp);
581 }
582
583//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header");
584}
585
586static
587void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
588 u16 offset,
589 const u8 *mac)
590{
591 u16 data;
592
593 offset |= 0x0020;
594 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
595
596 data = mac[0];
597 data |= mac[1] << 8;
598 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
599 data = mac[2];
600 data |= mac[3] << 8;
601 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
602 data = mac[4];
603 data |= mac[5] << 8;
604 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
605}
606
607static inline
608void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
609 u16 offset)
610{
611 const u8 zero_addr[ETH_ALEN] = { 0 };
612
613 bcm43xx_macfilter_set(bcm, offset, zero_addr);
614}
615
616static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
617{
618 const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
619 const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
620 u8 mac_bssid[ETH_ALEN * 2];
621 int i;
622
623 memcpy(mac_bssid, mac, ETH_ALEN);
624 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
625
626 /* Write our MAC address and BSSID to template ram */
627 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
628 bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
629 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
630 bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
631 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
632 bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
633}
634
635static inline
636void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
637{
638 /* slot_time is in usec. */
639 if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G)
640 return;
641 bcm43xx_write16(bcm, 0x684, 510 + slot_time);
642 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
643}
644
645static inline
646void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
647{
648 bcm43xx_set_slot_time(bcm, 9);
649}
650
651static inline
652void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
653{
654 bcm43xx_set_slot_time(bcm, 20);
655}
656
657//FIXME: rename this func?
658static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
659{
660 bcm43xx_mac_suspend(bcm);
661 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
662
663 bcm43xx_ram_write(bcm, 0x0026, 0x0000);
664 bcm43xx_ram_write(bcm, 0x0028, 0x0000);
665 bcm43xx_ram_write(bcm, 0x007E, 0x0000);
666 bcm43xx_ram_write(bcm, 0x0080, 0x0000);
667 bcm43xx_ram_write(bcm, 0x047E, 0x0000);
668 bcm43xx_ram_write(bcm, 0x0480, 0x0000);
669
670 if (bcm->current_core->rev < 3) {
671 bcm43xx_write16(bcm, 0x0610, 0x8000);
672 bcm43xx_write16(bcm, 0x060E, 0x0000);
673 } else
674 bcm43xx_write32(bcm, 0x0188, 0x80000000);
675
676 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
677
678 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
679 ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
680 bcm43xx_short_slot_timing_enable(bcm);
681
682 bcm43xx_mac_enable(bcm);
683}
684
685//FIXME: rename this func?
686static void bcm43xx_associate(struct bcm43xx_private *bcm,
687 const u8 *mac)
688{
689 memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
690
691 bcm43xx_mac_suspend(bcm);
692 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
693 bcm43xx_write_mac_bssid_templates(bcm);
694 bcm43xx_mac_enable(bcm);
695}
696
697/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
698 * Returns the _previously_ enabled IRQ mask.
699 */
700static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
701{
702 u32 old_mask;
703
704 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
705 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
706
707 return old_mask;
708}
709
710/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
711 * Returns the _previously_ enabled IRQ mask.
712 */
713static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
714{
715 u32 old_mask;
716
717 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
718 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
719
720 return old_mask;
721}
722
723/* Make sure we don't receive more data from the device. */
724static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
725{
726 u32 old;
727 unsigned long flags;
728
729 spin_lock_irqsave(&bcm->lock, flags);
730 if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
731 spin_unlock_irqrestore(&bcm->lock, flags);
732 return -EBUSY;
733 }
734 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
735 tasklet_disable(&bcm->isr_tasklet);
736 spin_unlock_irqrestore(&bcm->lock, flags);
737 if (oldstate)
738 *oldstate = old;
739
740 return 0;
741}
742
743static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
744{
745 u32 radio_id;
746 u16 manufact;
747 u16 version;
748 u8 revision;
749 s8 i;
750
751 if (bcm->chip_id == 0x4317) {
752 if (bcm->chip_rev == 0x00)
753 radio_id = 0x3205017F;
754 else if (bcm->chip_rev == 0x01)
755 radio_id = 0x4205017F;
756 else
757 radio_id = 0x5205017F;
758 } else {
759 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
760 radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
761 radio_id <<= 16;
762 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
763 radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
764 }
765
766 manufact = (radio_id & 0x00000FFF);
767 version = (radio_id & 0x0FFFF000) >> 12;
768 revision = (radio_id & 0xF0000000) >> 28;
769
770 dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
771 radio_id, manufact, version, revision);
772
773 switch (bcm->current_core->phy->type) {
774 case BCM43xx_PHYTYPE_A:
775 if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
776 goto err_unsupported_radio;
777 break;
778 case BCM43xx_PHYTYPE_B:
779 if ((version & 0xFFF0) != 0x2050)
780 goto err_unsupported_radio;
781 break;
782 case BCM43xx_PHYTYPE_G:
783 if (version != 0x2050)
784 goto err_unsupported_radio;
785 break;
786 }
787
788 bcm->current_core->radio->manufact = manufact;
789 bcm->current_core->radio->version = version;
790 bcm->current_core->radio->revision = revision;
791
792 /* Set default attenuation values. */
793 bcm->current_core->radio->txpower[0] = 2;
794 bcm->current_core->radio->txpower[1] = 2;
795 if (revision == 1)
796 bcm->current_core->radio->txpower[2] = 3;
797 else
798 bcm->current_core->radio->txpower[2] = 0;
799
800 /* Initialize the in-memory nrssi Lookup Table. */
801 for (i = 0; i < 64; i++)
802 bcm->current_core->radio->nrssi_lt[i] = i;
803
804 return 0;
805
806err_unsupported_radio:
807 printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
808 return -ENODEV;
809}
810
811static const char * bcm43xx_locale_iso(u8 locale)
812{
813 /* ISO 3166-1 country codes.
814 * Note that there aren't ISO 3166-1 codes for
815 * all or locales. (Not all locales are countries)
816 */
817 switch (locale) {
818 case BCM43xx_LOCALE_WORLD:
819 case BCM43xx_LOCALE_ALL:
820 return "XX";
821 case BCM43xx_LOCALE_THAILAND:
822 return "TH";
823 case BCM43xx_LOCALE_ISRAEL:
824 return "IL";
825 case BCM43xx_LOCALE_JORDAN:
826 return "JO";
827 case BCM43xx_LOCALE_CHINA:
828 return "CN";
829 case BCM43xx_LOCALE_JAPAN:
830 case BCM43xx_LOCALE_JAPAN_HIGH:
831 return "JP";
832 case BCM43xx_LOCALE_USA_CANADA_ANZ:
833 case BCM43xx_LOCALE_USA_LOW:
834 return "US";
835 case BCM43xx_LOCALE_EUROPE:
836 return "EU";
837 case BCM43xx_LOCALE_NONE:
838 return " ";
839 }
840 assert(0);
841 return " ";
842}
843
844static const char * bcm43xx_locale_string(u8 locale)
845{
846 switch (locale) {
847 case BCM43xx_LOCALE_WORLD:
848 return "World";
849 case BCM43xx_LOCALE_THAILAND:
850 return "Thailand";
851 case BCM43xx_LOCALE_ISRAEL:
852 return "Israel";
853 case BCM43xx_LOCALE_JORDAN:
854 return "Jordan";
855 case BCM43xx_LOCALE_CHINA:
856 return "China";
857 case BCM43xx_LOCALE_JAPAN:
858 return "Japan";
859 case BCM43xx_LOCALE_USA_CANADA_ANZ:
860 return "USA/Canada/ANZ";
861 case BCM43xx_LOCALE_EUROPE:
862 return "Europe";
863 case BCM43xx_LOCALE_USA_LOW:
864 return "USAlow";
865 case BCM43xx_LOCALE_JAPAN_HIGH:
866 return "JapanHigh";
867 case BCM43xx_LOCALE_ALL:
868 return "All";
869 case BCM43xx_LOCALE_NONE:
870 return "None";
871 }
872 assert(0);
873 return "";
874}
875
876static inline u8 bcm43xx_crc8(u8 crc, u8 data)
877{
878 static const u8 t[] = {
879 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
880 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
881 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
882 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
883 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
884 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
885 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
886 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
887 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
888 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
889 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
890 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
891 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
892 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
893 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
894 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
895 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
896 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
897 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
898 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
899 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
900 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
901 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
902 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
903 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
904 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
905 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
906 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
907 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
908 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
909 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
910 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
911 };
912 return t[crc ^ data];
913}
914
915u8 bcm43xx_sprom_crc(const u16 *sprom)
916{
917 int word;
918 u8 crc = 0xFF;
919
920 for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
921 crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
922 crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
923 }
924 crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
925 crc ^= 0xFF;
926
927 return crc;
928}
929
930
931static int bcm43xx_read_sprom(struct bcm43xx_private *bcm)
932{
933 int i;
934 u16 value;
935 u16 *sprom;
936 u8 crc, expected_crc;
937#ifdef CONFIG_BCM947XX
938 char *c;
939#endif
940
941 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
942 GFP_KERNEL);
943 if (!sprom) {
944 printk(KERN_ERR PFX "read_sprom OOM\n");
945 return -ENOMEM;
946 }
947#ifdef CONFIG_BCM947XX
948 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
949 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
950
951 if ((c = nvram_get("il0macaddr")) != NULL)
952 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
953
954 if ((c = nvram_get("et1macaddr")) != NULL)
955 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
956
957 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
958 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
959 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
960
961 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
962 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
963 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
964
965 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
966#else
967 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
968 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
969
970 /* CRC-8 check. */
971 crc = bcm43xx_sprom_crc(sprom);
972 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
973 if (crc != expected_crc) {
974 printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
975 "(0x%02X, expected: 0x%02X)\n",
976 crc, expected_crc);
977 }
978#endif
979
980 /* boardflags2 */
981 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
982 bcm->sprom.boardflags2 = value;
983
984 /* il0macaddr */
985 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
986 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
987 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
988 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
989 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
990 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
991
992 /* et0macaddr */
993 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
994 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
995 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
996 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
997 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
998 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
999
1000 /* et1macaddr */
1001 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
1002 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
1003 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
1004 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
1005 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
1006 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
1007
1008 /* ethernet phy settings */
1009 value = sprom[BCM43xx_SPROM_ETHPHY];
1010 bcm->sprom.et0phyaddr = (value & 0x001F);
1011 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
1012 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
1013 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
1014
1015 /* boardrev, antennas, locale */
1016 value = sprom[BCM43xx_SPROM_BOARDREV];
1017 bcm->sprom.boardrev = (value & 0x00FF);
1018 bcm->sprom.locale = (value & 0x0F00) >> 8;
1019 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
1020 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
1021 if (modparam_locale != -1) {
1022 if (modparam_locale >= 0 && modparam_locale <= 11) {
1023 bcm->sprom.locale = modparam_locale;
1024 printk(KERN_WARNING PFX "Operating with modified "
1025 "LocaleCode %u (%s)\n",
1026 bcm->sprom.locale,
1027 bcm43xx_locale_string(bcm->sprom.locale));
1028 } else {
1029 printk(KERN_WARNING PFX "Module parameter \"locale\" "
1030 "invalid value. (0 - 11)\n");
1031 }
1032 }
1033
1034 /* pa0b* */
1035 value = sprom[BCM43xx_SPROM_PA0B0];
1036 bcm->sprom.pa0b0 = value;
1037 value = sprom[BCM43xx_SPROM_PA0B1];
1038 bcm->sprom.pa0b1 = value;
1039 value = sprom[BCM43xx_SPROM_PA0B2];
1040 bcm->sprom.pa0b2 = value;
1041
1042 /* wl0gpio* */
1043 value = sprom[BCM43xx_SPROM_WL0GPIO0];
1044 if (value == 0x0000)
1045 value = 0xFFFF;
1046 bcm->sprom.wl0gpio0 = value & 0x00FF;
1047 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
1048 value = sprom[BCM43xx_SPROM_WL0GPIO2];
1049 if (value == 0x0000)
1050 value = 0xFFFF;
1051 bcm->sprom.wl0gpio2 = value & 0x00FF;
1052 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
1053
1054 /* maxpower */
1055 value = sprom[BCM43xx_SPROM_MAXPWR];
1056 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
1057 bcm->sprom.maxpower_bgphy = value & 0x00FF;
1058
1059 /* pa1b* */
1060 value = sprom[BCM43xx_SPROM_PA1B0];
1061 bcm->sprom.pa1b0 = value;
1062 value = sprom[BCM43xx_SPROM_PA1B1];
1063 bcm->sprom.pa1b1 = value;
1064 value = sprom[BCM43xx_SPROM_PA1B2];
1065 bcm->sprom.pa1b2 = value;
1066
1067 /* idle tssi target */
1068 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
1069 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
1070 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
1071
1072 /* boardflags */
1073 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
1074 if (value == 0xFFFF)
1075 value = 0x0000;
1076 bcm->sprom.boardflags = value;
1077
1078 /* antenna gain */
1079 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
1080 if (value == 0x0000 || value == 0xFFFF)
1081 value = 0x0202;
1082 /* convert values to Q5.2 */
1083 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
1084 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
1085
1086 kfree(sprom);
1087
1088 return 0;
1089}
1090
1091static int bcm43xx_channel_is_allowed(struct bcm43xx_private *bcm, u8 channel,
1092 u8 *max_power, u8 *flags)
1093{
1094 /* THIS FUNCTION DOES _NOT_ ENFORCE REGULATORY DOMAIN COMPLIANCE.
1095 * It is only a helper function to make life easier to
1096 * select legal channels and transmission powers.
1097 */
1098
1099 u8 phytype = bcm->current_core->phy->type;
1100 int allowed = 0;
1101
1102 *max_power = 0;
1103 *flags = 0;
1104
1105 //FIXME: Set max_power and maybe flags
1106 /*FIXME: Allowed channels are sometimes different for outdoor
1107 * or indoor use. See modparam_outdoor.
1108 */
1109 /* From b specs Max Power BPHY:
1110 * USA: 1000mW
1111 * Europe: 100mW
1112 * Japan: 10mW/MHz
1113 */
1114
1115 switch (bcm->sprom.locale) {
1116 case BCM43xx_LOCALE_WORLD:
1117 if (phytype == BCM43xx_PHYTYPE_A) {
1118 allowed = 1;//FIXME
1119 } else if (phytype == BCM43xx_PHYTYPE_B) {
1120 if (channel >= 1 && channel <= 13)
1121 allowed = 1;
1122 } else {
1123 if (channel >= 1 && channel <= 13)
1124 allowed = 1;
1125 }
1126 break;
1127 case BCM43xx_LOCALE_THAILAND:
1128 if (phytype == BCM43xx_PHYTYPE_A) {
1129 allowed = 1;//FIXME
1130 } else if (phytype == BCM43xx_PHYTYPE_B) {
1131 if (channel >= 1 && channel <= 14)
1132 allowed = 1;
1133 } else {
1134 if (channel >= 1 && channel <= 14)
1135 allowed = 1;
1136 }
1137 break;
1138 case BCM43xx_LOCALE_ISRAEL:
1139 if (phytype == BCM43xx_PHYTYPE_A) {
1140 allowed = 1;//FIXME
1141 } else if (phytype == BCM43xx_PHYTYPE_B) {
1142 if (channel >= 5 && channel <= 7)
1143 allowed = 1;
1144 } else {
1145 if (channel >= 5 && channel <= 7)
1146 allowed = 1;
1147 }
1148 break;
1149 case BCM43xx_LOCALE_JORDAN:
1150 if (phytype == BCM43xx_PHYTYPE_A) {
1151 allowed = 1;//FIXME
1152 } else if (phytype == BCM43xx_PHYTYPE_B) {
1153 if (channel >= 10 && channel <= 13)
1154 allowed = 1;
1155 } else {
1156 if (channel >= 10 && channel <= 13)
1157 allowed = 1;
1158 }
1159 break;
1160 case BCM43xx_LOCALE_CHINA:
1161 if (phytype == BCM43xx_PHYTYPE_A) {
1162 allowed = 1;//FIXME
1163 } else if (phytype == BCM43xx_PHYTYPE_B) {
1164 if (channel >= 1 && channel <= 13)
1165 allowed = 1;
1166 } else {
1167 if (channel >= 1 && channel <= 13)
1168 allowed = 1;
1169 }
1170 break;
1171 case BCM43xx_LOCALE_JAPAN:
1172 if (phytype == BCM43xx_PHYTYPE_A) {
1173 allowed = 1;//FIXME
1174 } else if (phytype == BCM43xx_PHYTYPE_B) {
1175 //FIXME: This seems to be wrong.
1176 if (channel >= 1 && channel <= 14)
1177 allowed = 1;
1178 } else {
1179 //FIXME: This seems to be wrong.
1180 if (channel >= 1 && channel <= 14)
1181 allowed = 1;
1182 }
1183 break;
1184 case BCM43xx_LOCALE_USA_CANADA_ANZ:
1185 if (phytype == BCM43xx_PHYTYPE_A) {
1186 allowed = 1;//FIXME
1187 } else if (phytype == BCM43xx_PHYTYPE_B) {
1188 if (channel >= 1 && channel <= 13)
1189 allowed = 1;
1190 } else {
1191 if (channel >= 1 && channel <= 11)
1192 allowed = 1;
1193 }
1194 break;
1195 case BCM43xx_LOCALE_EUROPE:
1196 if (phytype == BCM43xx_PHYTYPE_A) {
1197 allowed = 1;//FIXME
1198 } else if (phytype == BCM43xx_PHYTYPE_B) {
1199 if (channel >= 1 && channel <= 13)
1200 allowed = 1;
1201 } else {
1202 if (channel >= 1 && channel <= 13)
1203 allowed = 1;
1204 }
1205 break;
1206 case BCM43xx_LOCALE_USA_LOW:
1207 if (phytype == BCM43xx_PHYTYPE_A) {
1208 allowed = 1;//FIXME
1209 } else if (phytype == BCM43xx_PHYTYPE_B) {
1210 if (channel >= 1 && channel <= 13)
1211 allowed = 1;
1212 } else {
1213 if (channel >= 1 && channel <= 11)
1214 allowed = 1;
1215 }
1216 break;
1217 case BCM43xx_LOCALE_JAPAN_HIGH:
1218 if (phytype == BCM43xx_PHYTYPE_A) {
1219 allowed = 1;//FIXME
1220 } else if (phytype == BCM43xx_PHYTYPE_B) {
1221 //FIXME?
1222 if (channel >= 1 && channel <= 14)
1223 allowed = 1;
1224 } else {
1225 if (channel >= 1 && channel <= 14)
1226 allowed = 1;
1227 }
1228 break;
1229 case BCM43xx_LOCALE_ALL:
1230 allowed = 1;
1231 break;
1232 case BCM43xx_LOCALE_NONE:
1233 break;
1234 default:
1235 assert(0);
1236 }
1237
1238 return allowed;
1239}
1240
1241static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
1242{
1243 struct ieee80211_geo geo;
1244 struct ieee80211_channel *chan;
1245 int have_a = 0, have_bg = 0;
1246 int i, num80211;
1247 u8 channel, flags, max_power;
1248 struct bcm43xx_phyinfo *phy;
1249 const char *iso_country;
1250
1251 memset(&geo, 0, sizeof(geo));
1252 num80211 = bcm43xx_num_80211_cores(bcm);
1253 for (i = 0; i < num80211; i++) {
1254 phy = bcm->phy + i;
1255 switch (phy->type) {
1256 case BCM43xx_PHYTYPE_B:
1257 case BCM43xx_PHYTYPE_G:
1258 have_bg = 1;
1259 break;
1260 case BCM43xx_PHYTYPE_A:
1261 have_a = 1;
1262 break;
1263 default:
1264 assert(0);
1265 }
1266 }
1267 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
1268
1269 if (have_a) {
1270 for (i = 0, channel = 0; channel < 201; channel++) {
1271 if (!bcm43xx_channel_is_allowed(bcm, channel,
1272 &max_power, &flags))
1273 continue;
1274 chan = &geo.a[i++];
1275 chan->freq = bcm43xx_channel_to_freq(bcm, channel);
1276 chan->channel = channel;
1277 chan->flags = flags;
1278 chan->max_power = max_power;
1279 }
1280 geo.a_channels = i;
1281 }
1282 if (have_bg) {
1283 for (i = 0, channel = 1; channel < 15; channel++) {
1284 if (!bcm43xx_channel_is_allowed(bcm, channel,
1285 &max_power, &flags))
1286 continue;
1287 chan = &geo.bg[i++];
1288 chan->freq = bcm43xx_channel_to_freq(bcm, channel);
1289 chan->channel = channel;
1290 chan->flags = flags;
1291 chan->max_power = max_power;
1292 }
1293 geo.bg_channels = i;
1294 }
1295 memcpy(geo.name, iso_country, 2);
1296 if (0 /*TODO: Outdoor use only */)
1297 geo.name[2] = 'O';
1298 else if (0 /*TODO: Indoor use only */)
1299 geo.name[2] = 'I';
1300 else
1301 geo.name[2] = ' ';
1302 geo.name[3] = '\0';
1303
1304 ieee80211_set_geo(bcm->ieee, &geo);
1305}
1306
1307/* DummyTransmission function, as documented on
1308 * http://bcm-specs.sipsolutions.net/DummyTransmission
1309 */
1310void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
1311{
1312 unsigned int i, max_loop;
1313 u16 value = 0;
1314 u32 buffer[5] = {
1315 0x00000000,
1316 0x0000D400,
1317 0x00000000,
1318 0x00000001,
1319 0x00000000,
1320 };
1321
1322 switch (bcm->current_core->phy->type) {
1323 case BCM43xx_PHYTYPE_A:
1324 max_loop = 0x1E;
1325 buffer[0] = 0xCC010200;
1326 break;
1327 case BCM43xx_PHYTYPE_B:
1328 case BCM43xx_PHYTYPE_G:
1329 max_loop = 0xFA;
1330 buffer[0] = 0x6E840B00;
1331 break;
1332 default:
1333 assert(0);
1334 return;
1335 }
1336
1337 for (i = 0; i < 5; i++)
1338 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1339
1340 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1341
1342 bcm43xx_write16(bcm, 0x0568, 0x0000);
1343 bcm43xx_write16(bcm, 0x07C0, 0x0000);
1344 bcm43xx_write16(bcm, 0x050C, ((bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
1345 bcm43xx_write16(bcm, 0x0508, 0x0000);
1346 bcm43xx_write16(bcm, 0x050A, 0x0000);
1347 bcm43xx_write16(bcm, 0x054C, 0x0000);
1348 bcm43xx_write16(bcm, 0x056A, 0x0014);
1349 bcm43xx_write16(bcm, 0x0568, 0x0826);
1350 bcm43xx_write16(bcm, 0x0500, 0x0000);
1351 bcm43xx_write16(bcm, 0x0502, 0x0030);
1352
1353 for (i = 0x00; i < max_loop; i++) {
1354 value = bcm43xx_read16(bcm, 0x050E);
1355 if ((value & 0x0080) != 0)
1356 break;
1357 udelay(10);
1358 }
1359 for (i = 0x00; i < 0x0A; i++) {
1360 value = bcm43xx_read16(bcm, 0x050E);
1361 if ((value & 0x0400) != 0)
1362 break;
1363 udelay(10);
1364 }
1365 for (i = 0x00; i < 0x0A; i++) {
1366 value = bcm43xx_read16(bcm, 0x0690);
1367 if ((value & 0x0100) == 0)
1368 break;
1369 udelay(10);
1370 }
1371}
1372
1373static void key_write(struct bcm43xx_private *bcm,
1374 u8 index, u8 algorithm, const u16 *key)
1375{
1376 unsigned int i, basic_wep = 0;
1377 u32 offset;
1378 u16 value;
1379
1380 /* Write associated key information */
1381 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1382 ((index << 4) | (algorithm & 0x0F)));
1383
1384 /* The first 4 WEP keys need extra love */
1385 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1386 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1387 basic_wep = 1;
1388
1389 /* Write key payload, 8 little endian words */
1390 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1391 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1392 value = cpu_to_le16(key[i]);
1393 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1394 offset + (i * 2), value);
1395
1396 if (!basic_wep)
1397 continue;
1398
1399 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1400 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1401 value);
1402 }
1403}
1404
1405static void keymac_write(struct bcm43xx_private *bcm,
1406 u8 index, const u32 *addr)
1407{
1408 /* for keys 0-3 there is no associated mac address */
1409 if (index < 4)
1410 return;
1411
1412 index -= 4;
1413 if (bcm->current_core->rev >= 5) {
1414 bcm43xx_shm_write32(bcm,
1415 BCM43xx_SHM_HWMAC,
1416 index * 2,
1417 cpu_to_be32(*addr));
1418 bcm43xx_shm_write16(bcm,
1419 BCM43xx_SHM_HWMAC,
1420 (index * 2) + 1,
1421 cpu_to_be16(*((u16 *)(addr + 1))));
1422 } else {
1423 if (index < 8) {
1424 TODO(); /* Put them in the macaddress filter */
1425 } else {
1426 TODO();
1427 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1428 Keep in mind to update the count of keymacs in 0x003E as well! */
1429 }
1430 }
1431}
1432
1433static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1434 u8 index, u8 algorithm,
1435 const u8 *_key, int key_len,
1436 const u8 *mac_addr)
1437{
1438 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1439
1440 if (index >= ARRAY_SIZE(bcm->key))
1441 return -EINVAL;
1442 if (key_len > ARRAY_SIZE(key))
1443 return -EINVAL;
1444 if (algorithm < 1 || algorithm > 5)
1445 return -EINVAL;
1446
1447 memcpy(key, _key, key_len);
1448 key_write(bcm, index, algorithm, (const u16 *)key);
1449 keymac_write(bcm, index, (const u32 *)mac_addr);
1450
1451 bcm->key[index].algorithm = algorithm;
1452
1453 return 0;
1454}
1455
1456static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1457{
1458 static const u32 zero_mac[2] = { 0 };
1459 unsigned int i,j, nr_keys = 54;
1460 u16 offset;
1461
1462 if (bcm->current_core->rev < 5)
1463 nr_keys = 16;
1464 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1465
1466 for (i = 0; i < nr_keys; i++) {
1467 bcm->key[i].enabled = 0;
1468 /* returns for i < 4 immediately */
1469 keymac_write(bcm, i, zero_mac);
1470 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1471 0x100 + (i * 2), 0x0000);
1472 for (j = 0; j < 8; j++) {
1473 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1474 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1475 offset, 0x0000);
1476 }
1477 }
1478 dprintk(KERN_INFO PFX "Keys cleared\n");
1479}
1480
1481/* Puts the index of the current core into user supplied core variable.
1482 * This function reads the value from the device.
1483 * Almost always you don't want to call this, but use bcm->current_core
1484 */
1485static inline
1486int _get_current_core(struct bcm43xx_private *bcm, int *core)
1487{
1488 int err;
1489
1490 err = bcm43xx_pci_read_config32(bcm, BCM43xx_REG_ACTIVE_CORE, core);
1491 if (unlikely(err)) {
1492 dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE read failed!\n");
1493 return -ENODEV;
1494 }
1495 *core = (*core - 0x18000000) / 0x1000;
1496
1497 return 0;
1498}
1499
1500/* Lowlevel core-switch function. This is only to be used in
1501 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1502 */
1503static int _switch_core(struct bcm43xx_private *bcm, int core)
1504{
1505 int err;
1506 int attempts = 0;
1507 int current_core = -1;
1508
1509 assert(core >= 0);
1510
1511 err = _get_current_core(bcm, &current_core);
1512 if (unlikely(err))
1513 goto out;
1514
1515 /* Write the computed value to the register. This doesn't always
1516 succeed so we retry BCM43xx_SWITCH_CORE_MAX_RETRIES times */
1517 while (current_core != core) {
1518 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) {
1519 err = -ENODEV;
1520 printk(KERN_ERR PFX
1521 "unable to switch to core %u, retried %i times\n",
1522 core, attempts);
1523 goto out;
1524 }
1525 err = bcm43xx_pci_write_config32(bcm, BCM43xx_REG_ACTIVE_CORE,
1526 (core * 0x1000) + 0x18000000);
1527 if (unlikely(err)) {
1528 dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE write failed!\n");
1529 continue;
1530 }
1531 _get_current_core(bcm, &current_core);
1532#ifdef CONFIG_BCM947XX
1533 if (bcm->pci_dev->bus->number == 0)
1534 bcm->current_core_offset = 0x1000 * core;
1535 else
1536 bcm->current_core_offset = 0;
1537#endif
1538 }
1539
1540 assert(err == 0);
1541out:
1542 return err;
1543}
1544
1545int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1546{
1547 int err;
1548
1549 if (!new_core)
1550 return 0;
1551
1552 if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE))
1553 return -ENODEV;
1554 if (bcm->current_core == new_core)
1555 return 0;
1556 err = _switch_core(bcm, new_core->index);
1557 if (!err)
1558 bcm->current_core = new_core;
1559
1560 return err;
1561}
1562
1563static inline int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
1564{
1565 u32 value;
1566
1567 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1568 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1569 | BCM43xx_SBTMSTATELOW_REJECT;
1570
1571 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1572}
1573
1574/* disable current core */
1575static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1576{
1577 u32 sbtmstatelow;
1578 u32 sbtmstatehigh;
1579 int i;
1580
1581 /* fetch sbtmstatelow from core information registers */
1582 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1583
1584 /* core is already in reset */
1585 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1586 goto out;
1587
1588 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1589 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1590 BCM43xx_SBTMSTATELOW_REJECT;
1591 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1592
1593 for (i = 0; i < 1000; i++) {
1594 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1595 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1596 i = -1;
1597 break;
1598 }
1599 udelay(10);
1600 }
1601 if (i != -1) {
1602 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1603 return -EBUSY;
1604 }
1605
1606 for (i = 0; i < 1000; i++) {
1607 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1608 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1609 i = -1;
1610 break;
1611 }
1612 udelay(10);
1613 }
1614 if (i != -1) {
1615 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1616 return -EBUSY;
1617 }
1618
1619 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1620 BCM43xx_SBTMSTATELOW_REJECT |
1621 BCM43xx_SBTMSTATELOW_RESET |
1622 BCM43xx_SBTMSTATELOW_CLOCK |
1623 core_flags;
1624 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1625 udelay(10);
1626 }
1627
1628 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1629 BCM43xx_SBTMSTATELOW_REJECT |
1630 core_flags;
1631 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1632
1633out:
1634 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED;
1635 return 0;
1636}
1637
1638/* enable (reset) current core */
1639static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1640{
1641 u32 sbtmstatelow;
1642 u32 sbtmstatehigh;
1643 u32 sbimstate;
1644 int err;
1645
1646 err = bcm43xx_core_disable(bcm, core_flags);
1647 if (err)
1648 goto out;
1649
1650 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1651 BCM43xx_SBTMSTATELOW_RESET |
1652 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1653 core_flags;
1654 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1655 udelay(1);
1656
1657 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1658 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1659 sbtmstatehigh = 0x00000000;
1660 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1661 }
1662
1663 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1664 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1665 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1666 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1667 }
1668
1669 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1670 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1671 core_flags;
1672 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1673 udelay(1);
1674
1675 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1676 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1677 udelay(1);
1678
1679 bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED;
1680 assert(err == 0);
1681out:
1682 return err;
1683}
1684
1685/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1686void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1687{
1688 u32 flags = 0x00040000;
1689
1690 if ((bcm43xx_core_enabled(bcm)) && (!bcm->pio_mode)) {
1691//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1692#ifndef CONFIG_BCM947XX
1693 /* reset all used DMA controllers. */
1694 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1695 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1696 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1697 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1698 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1699 if (bcm->current_core->rev < 5)
1700 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1701#endif
1702 }
1703 if (bcm->shutting_down) {
1704 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1705 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1706 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1707 } else {
1708 if (connect_phy)
1709 flags |= 0x20000000;
1710 bcm43xx_phy_connect(bcm, connect_phy);
1711 bcm43xx_core_enable(bcm, flags);
1712 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1713 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1714 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1715 | BCM43xx_SBF_400);
1716 }
1717}
1718
1719static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1720{
1721 bcm43xx_radio_turn_off(bcm);
1722 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1723 bcm43xx_core_disable(bcm, 0);
1724}
1725
1726/* Mark the current 80211 core inactive.
1727 * "active_80211_core" is the other 80211 core, which is used.
1728 */
1729static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1730 struct bcm43xx_coreinfo *active_80211_core)
1731{
1732 u32 sbtmstatelow;
1733 struct bcm43xx_coreinfo *old_core;
1734 int err = 0;
1735
1736 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1737 bcm43xx_radio_turn_off(bcm);
1738 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1739 sbtmstatelow &= ~0x200a0000;
1740 sbtmstatelow |= 0xa0000;
1741 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1742 udelay(1);
1743 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1744 sbtmstatelow &= ~0xa0000;
1745 sbtmstatelow |= 0x80000;
1746 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1747 udelay(1);
1748
1749 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
1750 old_core = bcm->current_core;
1751 err = bcm43xx_switch_core(bcm, active_80211_core);
1752 if (err)
1753 goto out;
1754 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1755 sbtmstatelow &= ~0x20000000;
1756 sbtmstatelow |= 0x20000000;
1757 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1758 err = bcm43xx_switch_core(bcm, old_core);
1759 }
1760
1761out:
1762 return err;
1763}
1764
1765static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm)
1766{
1767 u32 v0, v1;
1768 u16 tmp;
1769 struct bcm43xx_xmitstatus stat;
1770
1771 assert(bcm->current_core->id == BCM43xx_COREID_80211);
1772 assert(bcm->current_core->rev >= 5);
1773
1774 while (1) {
1775 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1776 if (!v0)
1777 break;
1778 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1779
1780 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1781 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1782 stat.flags = tmp & 0xFF;
1783 stat.cnt1 = (tmp & 0x0F00) >> 8;
1784 stat.cnt2 = (tmp & 0xF000) >> 12;
1785 stat.seq = (u16)(v1 & 0xFFFF);
1786 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1787
1788 bcm43xx_debugfs_log_txstat(bcm, &stat);
1789
1790 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1791 continue;
1792 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1793 //TODO: packet was not acked (was lost)
1794 }
1795 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1796
1797 if (bcm->pio_mode)
1798 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1799 else
1800 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1801 }
1802}
1803
1804static inline void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
1805{
1806 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1807 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1808 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1809 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1810 assert(bcm->noisecalc.core_at_start == bcm->current_core);
1811 assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel);
1812}
1813
1814static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1815{
1816 /* Top half of Link Quality calculation. */
1817
1818 if (bcm->noisecalc.calculation_running)
1819 return;
1820 bcm->noisecalc.core_at_start = bcm->current_core;
1821 bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel;
1822 bcm->noisecalc.calculation_running = 1;
1823 bcm->noisecalc.nr_samples = 0;
1824
1825 bcm43xx_generate_noise_sample(bcm);
1826}
1827
1828static inline void handle_irq_noise(struct bcm43xx_private *bcm)
1829{
1830 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1831 u16 tmp;
1832 u8 noise[4];
1833 u8 i, j;
1834 s32 average;
1835
1836 /* Bottom half of Link Quality calculation. */
1837
1838 assert(bcm->noisecalc.calculation_running);
1839 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1840 bcm->noisecalc.channel_at_start != radio->channel)
1841 goto drop_calculation;
1842 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1843 noise[0] = (tmp & 0x00FF);
1844 noise[1] = (tmp & 0xFF00) >> 8;
1845 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1846 noise[2] = (tmp & 0x00FF);
1847 noise[3] = (tmp & 0xFF00) >> 8;
1848 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1849 noise[2] == 0x7F || noise[3] == 0x7F)
1850 goto generate_new;
1851
1852 /* Get the noise samples. */
1853 assert(bcm->noisecalc.nr_samples <= 8);
1854 i = bcm->noisecalc.nr_samples;
1855 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1856 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1857 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1858 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1859 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1860 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1861 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1862 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1863 bcm->noisecalc.nr_samples++;
1864 if (bcm->noisecalc.nr_samples == 8) {
1865 /* Calculate the Link Quality by the noise samples. */
1866 average = 0;
1867 for (i = 0; i < 8; i++) {
1868 for (j = 0; j < 4; j++)
1869 average += bcm->noisecalc.samples[i][j];
1870 }
1871 average /= (8 * 4);
1872 average *= 125;
1873 average += 64;
1874 average /= 128;
1875 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1876 tmp = (tmp / 128) & 0x1F;
1877 if (tmp >= 8)
1878 average += 2;
1879 else
1880 average -= 25;
1881 if (tmp == 8)
1882 average -= 72;
1883 else
1884 average -= 48;
1885
1886 if (average > -65)
1887 bcm->stats.link_quality = 0;
1888 else if (average > -75)
1889 bcm->stats.link_quality = 1;
1890 else if (average > -85)
1891 bcm->stats.link_quality = 2;
1892 else
1893 bcm->stats.link_quality = 3;
1894// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1895drop_calculation:
1896 bcm->noisecalc.calculation_running = 0;
1897 return;
1898 }
1899generate_new:
1900 bcm43xx_generate_noise_sample(bcm);
1901}
1902
1903static inline
1904void handle_irq_ps(struct bcm43xx_private *bcm)
1905{
1906 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1907 ///TODO: PS TBTT
1908 } else {
1909 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1910 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1911 }
1912 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1913 bcm->reg124_set_0x4 = 1;
1914 //FIXME else set to false?
1915}
1916
1917static inline
1918void handle_irq_reg124(struct bcm43xx_private *bcm)
1919{
1920 if (!bcm->reg124_set_0x4)
1921 return;
1922 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1923 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1924 | 0x4);
1925 //FIXME: reset reg124_set_0x4 to false?
1926}
1927
1928static inline
1929void handle_irq_pmq(struct bcm43xx_private *bcm)
1930{
1931 u32 tmp;
1932
1933 //TODO: AP mode.
1934
1935 while (1) {
1936 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1937 if (!(tmp & 0x00000008))
1938 break;
1939 }
1940 /* 16bit write is odd, but correct. */
1941 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1942}
1943
1944static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1945 u16 ram_offset, u16 shm_size_offset)
1946{
1947 u32 value;
1948 u16 size = 0;
1949
1950 /* Timestamp. */
1951 //FIXME: assumption: The chip sets the timestamp
1952 value = 0;
1953 bcm43xx_ram_write(bcm, ram_offset++, value);
1954 bcm43xx_ram_write(bcm, ram_offset++, value);
1955 size += 8;
1956
1957 /* Beacon Interval / Capability Information */
1958 value = 0x0000;//FIXME: Which interval?
1959 value |= (1 << 0) << 16; /* ESS */
1960 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1961 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1962 if (!bcm->ieee->open_wep)
1963 value |= (1 << 4) << 16; /* Privacy */
1964 bcm43xx_ram_write(bcm, ram_offset++, value);
1965 size += 4;
1966
1967 /* SSID */
1968 //TODO
1969
1970 /* FH Parameter Set */
1971 //TODO
1972
1973 /* DS Parameter Set */
1974 //TODO
1975
1976 /* CF Parameter Set */
1977 //TODO
1978
1979 /* TIM */
1980 //TODO
1981
1982 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1983}
1984
1985static inline
1986void handle_irq_beacon(struct bcm43xx_private *bcm)
1987{
1988 u32 status;
1989
1990 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1991 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1992
1993 if ((status & 0x1) && (status & 0x2)) {
1994 /* ACK beacon IRQ. */
1995 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1996 BCM43xx_IRQ_BEACON);
1997 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1998 return;
1999 }
2000 if (!(status & 0x1)) {
2001 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
2002 status |= 0x1;
2003 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
2004 }
2005 if (!(status & 0x2)) {
2006 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
2007 status |= 0x2;
2008 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
2009 }
2010}
2011
2012/* Debug helper for irq bottom-half to print all reason registers. */
2013#define bcmirq_print_reasons(description) \
2014 do { \
2015 dprintkl(KERN_ERR PFX description "\n" \
2016 KERN_ERR PFX " Generic Reason: 0x%08x\n" \
2017 KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \
2018 KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \
2019 reason, \
2020 dma_reason[0], dma_reason[1], \
2021 dma_reason[2], dma_reason[3], \
2022 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \
2023 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \
2024 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \
2025 bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \
2026 } while (0)
2027
2028/* Interrupt handler bottom-half */
2029static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
2030{
2031 u32 reason;
2032 u32 dma_reason[4];
2033 int activity = 0;
2034 unsigned long flags;
2035
2036#ifdef CONFIG_BCM43XX_DEBUG
2037 u32 _handled = 0x00000000;
2038# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
2039#else
2040# define bcmirq_handled(irq) do { /* nothing */ } while (0)
2041#endif /* CONFIG_BCM43XX_DEBUG*/
2042
2043 spin_lock_irqsave(&bcm->lock, flags);
2044 reason = bcm->irq_reason;
2045 dma_reason[0] = bcm->dma_reason[0];
2046 dma_reason[1] = bcm->dma_reason[1];
2047 dma_reason[2] = bcm->dma_reason[2];
2048 dma_reason[3] = bcm->dma_reason[3];
2049
2050 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
2051 /* TX error. We get this when Template Ram is written in wrong endianess
2052 * in dummy_tx(). We also get this if something is wrong with the TX header
2053 * on DMA or PIO queues.
2054 * Maybe we get this in other error conditions, too.
2055 */
2056 bcmirq_print_reasons("XMIT ERROR");
2057 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
2058 }
2059
2060 if (reason & BCM43xx_IRQ_PS) {
2061 handle_irq_ps(bcm);
2062 bcmirq_handled(BCM43xx_IRQ_PS);
2063 }
2064
2065 if (reason & BCM43xx_IRQ_REG124) {
2066 handle_irq_reg124(bcm);
2067 bcmirq_handled(BCM43xx_IRQ_REG124);
2068 }
2069
2070 if (reason & BCM43xx_IRQ_BEACON) {
2071 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
2072 handle_irq_beacon(bcm);
2073 bcmirq_handled(BCM43xx_IRQ_BEACON);
2074 }
2075
2076 if (reason & BCM43xx_IRQ_PMQ) {
2077 handle_irq_pmq(bcm);
2078 bcmirq_handled(BCM43xx_IRQ_PMQ);
2079 }
2080
2081 if (reason & BCM43xx_IRQ_SCAN) {
2082 /*TODO*/
2083 //bcmirq_handled(BCM43xx_IRQ_SCAN);
2084 }
2085
2086 if (reason & BCM43xx_IRQ_NOISE) {
2087 handle_irq_noise(bcm);
2088 bcmirq_handled(BCM43xx_IRQ_NOISE);
2089 }
2090
2091 /* Check the DMA reason registers for received data. */
2092 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
2093 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
2094 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
2095 if (bcm->pio_mode)
2096 bcm43xx_pio_rx(bcm->current_core->pio->queue0);
2097 else
2098 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0);
2099 activity = 1;
2100 }
2101 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
2102 if (likely(bcm->current_core->rev < 5)) {
2103 if (bcm->pio_mode)
2104 bcm43xx_pio_rx(bcm->current_core->pio->queue3);
2105 else
2106 bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1);
2107 activity = 1;
2108 } else
2109 assert(0);
2110 }
2111 bcmirq_handled(BCM43xx_IRQ_RX);
2112
2113 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
2114 if (bcm->current_core->rev >= 5) {
2115 handle_irq_transmit_status(bcm);
2116 activity = 1;
2117 }
2118 //TODO: In AP mode, this also causes sending of powersave responses.
2119 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
2120 }
2121
2122 /* We get spurious IRQs, althought they are masked.
2123 * Assume they are void and ignore them.
2124 */
2125 bcmirq_handled(~(bcm->irq_savedstate));
2126 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
2127 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
2128#ifdef CONFIG_BCM43XX_DEBUG
2129 if (unlikely(reason & ~_handled)) {
2130 printkl(KERN_WARNING PFX
2131 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
2132 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2133 reason, (reason & ~_handled),
2134 dma_reason[0], dma_reason[1],
2135 dma_reason[2], dma_reason[3]);
2136 }
2137#endif
2138#undef bcmirq_handled
2139
2140 if (!modparam_noleds)
2141 bcm43xx_leds_update(bcm, activity);
2142 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2143 spin_unlock_irqrestore(&bcm->lock, flags);
2144}
2145
2146#undef bcmirq_print_reasons
2147
2148static inline
2149void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm,
2150 u32 reason, u32 mask)
2151{
2152 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
2153 & 0x0001dc00;
2154 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
2155 & 0x0000dc00;
2156 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
2157 & 0x0000dc00;
2158 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
2159 & 0x0001dc00;
2160
2161 if ((bcm->pio_mode) &&
2162 (bcm->current_core->rev < 3) &&
2163 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
2164 /* Apply a PIO specific workaround to the dma_reasons */
2165
2166#define apply_pio_workaround(BASE, QNUM) \
2167 do { \
2168 if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \
2169 bcm->dma_reason[QNUM] |= 0x00010000; \
2170 else \
2171 bcm->dma_reason[QNUM] &= ~0x00010000; \
2172 } while (0)
2173
2174 apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0);
2175 apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1);
2176 apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2);
2177 apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3);
2178
2179#undef apply_pio_workaround
2180 }
2181
2182 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
2183 reason & mask);
2184
2185 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
2186 bcm->dma_reason[0]);
2187 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
2188 bcm->dma_reason[1]);
2189 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
2190 bcm->dma_reason[2]);
2191 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
2192 bcm->dma_reason[3]);
2193}
2194
2195/* Interrupt handler top-half */
2196static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
2197{
2198 struct bcm43xx_private *bcm = dev_id;
2199 u32 reason, mask;
2200
2201 if (!bcm)
2202 return IRQ_NONE;
2203
2204 spin_lock(&bcm->lock);
2205
2206 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2207 if (reason == 0xffffffff) {
2208 /* irq not for us (shared irq) */
2209 spin_unlock(&bcm->lock);
2210 return IRQ_NONE;
2211 }
2212 mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
2213 if (!(reason & mask)) {
2214 spin_unlock(&bcm->lock);
2215 return IRQ_HANDLED;
2216 }
2217
2218 bcm43xx_interrupt_ack(bcm, reason, mask);
2219
2220 /* disable all IRQs. They are enabled again in the bottom half. */
2221 bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
2222
2223 /* save the reason code and call our bottom half. */
2224 bcm->irq_reason = reason;
2225 tasklet_schedule(&bcm->isr_tasklet);
2226
2227 spin_unlock(&bcm->lock);
2228
2229 return IRQ_HANDLED;
2230}
2231
2232static void bcm43xx_release_firmware(struct bcm43xx_private *bcm)
2233{
2234 if (bcm->firmware_norelease)
2235 return; /* Suspending or controller reset. */
2236 release_firmware(bcm->ucode);
2237 bcm->ucode = NULL;
2238 release_firmware(bcm->pcm);
2239 bcm->pcm = NULL;
2240 release_firmware(bcm->initvals0);
2241 bcm->initvals0 = NULL;
2242 release_firmware(bcm->initvals1);
2243 bcm->initvals1 = NULL;
2244}
2245
2246static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
2247{
2248 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
2249 u8 rev = bcm->current_core->rev;
2250 int err = 0;
2251 int nr;
2252 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
2253
2254 if (!bcm->ucode) {
2255 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
2256 (rev >= 5 ? 5 : rev),
2257 modparam_fwpostfix);
2258 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
2259 if (err) {
2260 printk(KERN_ERR PFX
2261 "Error: Microcode \"%s\" not available or load failed.\n",
2262 buf);
2263 goto error;
2264 }
2265 }
2266
2267 if (!bcm->pcm) {
2268 snprintf(buf, ARRAY_SIZE(buf),
2269 "bcm43xx_pcm%d%s.fw",
2270 (rev < 5 ? 4 : 5),
2271 modparam_fwpostfix);
2272 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
2273 if (err) {
2274 printk(KERN_ERR PFX
2275 "Error: PCM \"%s\" not available or load failed.\n",
2276 buf);
2277 goto error;
2278 }
2279 }
2280
2281 if (!bcm->initvals0) {
2282 if (rev == 2 || rev == 4) {
2283 switch (phy->type) {
2284 case BCM43xx_PHYTYPE_A:
2285 nr = 3;
2286 break;
2287 case BCM43xx_PHYTYPE_B:
2288 case BCM43xx_PHYTYPE_G:
2289 nr = 1;
2290 break;
2291 default:
2292 goto err_noinitval;
2293 }
2294
2295 } else if (rev >= 5) {
2296 switch (phy->type) {
2297 case BCM43xx_PHYTYPE_A:
2298 nr = 7;
2299 break;
2300 case BCM43xx_PHYTYPE_B:
2301 case BCM43xx_PHYTYPE_G:
2302 nr = 5;
2303 break;
2304 default:
2305 goto err_noinitval;
2306 }
2307 } else
2308 goto err_noinitval;
2309 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2310 nr, modparam_fwpostfix);
2311
2312 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
2313 if (err) {
2314 printk(KERN_ERR PFX
2315 "Error: InitVals \"%s\" not available or load failed.\n",
2316 buf);
2317 goto error;
2318 }
2319 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
2320 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2321 goto error;
2322 }
2323 }
2324
2325 if (!bcm->initvals1) {
2326 if (rev >= 5) {
2327 u32 sbtmstatehigh;
2328
2329 switch (phy->type) {
2330 case BCM43xx_PHYTYPE_A:
2331 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
2332 if (sbtmstatehigh & 0x00010000)
2333 nr = 9;
2334 else
2335 nr = 10;
2336 break;
2337 case BCM43xx_PHYTYPE_B:
2338 case BCM43xx_PHYTYPE_G:
2339 nr = 6;
2340 break;
2341 default:
2342 goto err_noinitval;
2343 }
2344 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2345 nr, modparam_fwpostfix);
2346
2347 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
2348 if (err) {
2349 printk(KERN_ERR PFX
2350 "Error: InitVals \"%s\" not available or load failed.\n",
2351 buf);
2352 goto error;
2353 }
2354 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
2355 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2356 goto error;
2357 }
2358 }
2359 }
2360
2361out:
2362 return err;
2363error:
2364 bcm43xx_release_firmware(bcm);
2365 goto out;
2366err_noinitval:
2367 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2368 err = -ENOENT;
2369 goto error;
2370}
2371
2372static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2373{
2374 const u32 *data;
2375 unsigned int i, len;
2376
2377#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2378 bcm43xx_mmioprint_enable(bcm);
2379#else
2380 bcm43xx_mmioprint_disable(bcm);
2381#endif
2382
2383 /* Upload Microcode. */
2384 data = (u32 *)(bcm->ucode->data);
2385 len = bcm->ucode->size / sizeof(u32);
2386 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2387 for (i = 0; i < len; i++) {
2388 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2389 be32_to_cpu(data[i]));
2390 udelay(10);
2391 }
2392
2393 /* Upload PCM data. */
2394 data = (u32 *)(bcm->pcm->data);
2395 len = bcm->pcm->size / sizeof(u32);
2396 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2397 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2398 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2399 for (i = 0; i < len; i++) {
2400 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2401 be32_to_cpu(data[i]));
2402 udelay(10);
2403 }
2404
2405#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2406 bcm43xx_mmioprint_disable(bcm);
2407#else
2408 bcm43xx_mmioprint_enable(bcm);
2409#endif
2410}
2411
2412static void bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2413 const struct bcm43xx_initval *data,
2414 const unsigned int len)
2415{
2416 u16 offset, size;
2417 u32 value;
2418 unsigned int i;
2419
2420 for (i = 0; i < len; i++) {
2421 offset = be16_to_cpu(data[i].offset);
2422 size = be16_to_cpu(data[i].size);
2423 value = be32_to_cpu(data[i].value);
2424
2425 if (size == 2)
2426 bcm43xx_write16(bcm, offset, value);
2427 else if (size == 4)
2428 bcm43xx_write32(bcm, offset, value);
2429 else
2430 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2431 }
2432}
2433
2434static void bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
2435{
2436#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2437 bcm43xx_mmioprint_enable(bcm);
2438#else
2439 bcm43xx_mmioprint_disable(bcm);
2440#endif
2441
2442 bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2443 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2444 if (bcm->initvals1) {
2445 bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2446 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2447 }
2448
2449#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT
2450 bcm43xx_mmioprint_disable(bcm);
2451#else
2452 bcm43xx_mmioprint_enable(bcm);
2453#endif
2454}
2455
2456static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2457{
2458 int res;
2459 unsigned int i;
2460 u32 data;
2461
2462 bcm->irq = bcm->pci_dev->irq;
2463#ifdef CONFIG_BCM947XX
2464 if (bcm->pci_dev->bus->number == 0) {
2465 struct pci_dev *d = NULL;
2466 /* FIXME: we will probably need more device IDs here... */
2467 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2468 if (d != NULL) {
2469 bcm->irq = d->irq;
2470 }
2471 }
2472#endif
2473 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
2474 SA_SHIRQ, DRV_NAME, bcm);
2475 if (res) {
2476 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
2477 return -EFAULT;
2478 }
2479 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2480 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2481 i = 0;
2482 while (1) {
2483 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2484 if (data == BCM43xx_IRQ_READY)
2485 break;
2486 i++;
2487 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2488 printk(KERN_ERR PFX "Card IRQ register not responding. "
2489 "Giving up.\n");
2490 free_irq(bcm->irq, bcm);
2491 return -ENODEV;
2492 }
2493 udelay(10);
2494 }
2495 // dummy read
2496 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2497
2498 return 0;
2499}
2500
2501/* Switch to the core used to write the GPIO register.
2502 * This is either the ChipCommon, or the PCI core.
2503 */
2504static inline int switch_to_gpio_core(struct bcm43xx_private *bcm)
2505{
2506 int err;
2507
2508 /* Where to find the GPIO register depends on the chipset.
2509 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2510 * control register. Otherwise the register at offset 0x6c in the
2511 * PCI core is the GPIO control register.
2512 */
2513 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2514 if (err == -ENODEV) {
2515 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2516 if (err == -ENODEV) {
2517 printk(KERN_ERR PFX "gpio error: "
2518 "Neither ChipCommon nor PCI core available!\n");
2519 return -ENODEV;
2520 } else if (err != 0)
2521 return -ENODEV;
2522 } else if (err != 0)
2523 return -ENODEV;
2524
2525 return 0;
2526}
2527
2528/* Initialize the GPIOs
2529 * http://bcm-specs.sipsolutions.net/GPIO
2530 */
2531static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2532{
2533 struct bcm43xx_coreinfo *old_core;
2534 int err;
2535 u32 mask, value;
2536
2537 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2538 value &= ~0xc000;
2539 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
2540
2541 mask = 0x0000001F;
2542 value = 0x0000000F;
2543 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL,
2544 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0);
2545 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2546 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2547
2548 old_core = bcm->current_core;
2549
2550 err = switch_to_gpio_core(bcm);
2551 if (err)
2552 return err;
2553
2554 if (bcm->current_core->rev >= 2){
2555 mask |= 0x10;
2556 value |= 0x10;
2557 }
2558 if (bcm->chip_id == 0x4301) {
2559 mask |= 0x60;
2560 value |= 0x60;
2561 }
2562 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
2563 mask |= 0x200;
2564 value |= 0x200;
2565 }
2566
2567 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
2568 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value);
2569
2570 err = bcm43xx_switch_core(bcm, old_core);
2571 assert(err == 0);
2572
2573 return 0;
2574}
2575
2576/* Turn off all GPIO stuff. Call this on module unload, for example. */
2577static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2578{
2579 struct bcm43xx_coreinfo *old_core;
2580 int err;
2581
2582 old_core = bcm->current_core;
2583 err = switch_to_gpio_core(bcm);
2584 if (err)
2585 return err;
2586 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2587 err = bcm43xx_switch_core(bcm, old_core);
2588 assert(err == 0);
2589
2590 return 0;
2591}
2592
2593/* http://bcm-specs.sipsolutions.net/EnableMac */
2594void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2595{
2596 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2597 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2598 | BCM43xx_SBF_MAC_ENABLED);
2599 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2600 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2601 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2602 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2603}
2604
2605/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2606void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2607{
2608 int i;
2609 u32 tmp;
2610
2611 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2612 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2613 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2614 & ~BCM43xx_SBF_MAC_ENABLED);
2615 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2616 for (i = 1000; i > 0; i--) {
2617 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2618 if (tmp & BCM43xx_IRQ_READY) {
2619 i = -1;
2620 break;
2621 }
2622 udelay(10);
2623 }
2624 if (!i)
2625 printkl(KERN_ERR PFX "Failed to suspend mac!\n");
2626}
2627
2628void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2629 int iw_mode)
2630{
2631 unsigned long flags;
2632 u32 status;
2633
2634 spin_lock_irqsave(&bcm->ieee->lock, flags);
2635 bcm->ieee->iw_mode = iw_mode;
2636 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2637 if (iw_mode == IW_MODE_MONITOR)
2638 bcm->net_dev->type = ARPHRD_IEEE80211;
2639 else
2640 bcm->net_dev->type = ARPHRD_ETHER;
2641
2642 if (!bcm->initialized)
2643 return;
2644
2645 bcm43xx_mac_suspend(bcm);
2646 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2647 /* Reset status to infrastructured mode */
2648 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
2649 /*FIXME: We actually set promiscuous mode as well, until we don't
2650 * get the HW mac filter working */
2651 status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC;
2652
2653 switch (iw_mode) {
2654 case IW_MODE_MONITOR:
2655 status |= (BCM43xx_SBF_MODE_PROMISC |
2656 BCM43xx_SBF_MODE_MONITOR);
2657 break;
2658 case IW_MODE_ADHOC:
2659 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2660 break;
2661 case IW_MODE_MASTER:
2662 case IW_MODE_SECOND:
2663 case IW_MODE_REPEAT:
2664 /* TODO: No AP/Repeater mode for now :-/ */
2665 TODO();
2666 break;
2667 case IW_MODE_INFRA:
2668 /* nothing to be done here... */
2669 break;
2670 default:
2671 printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode);
2672 }
2673
2674 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
2675 bcm43xx_mac_enable(bcm);
2676}
2677
2678/* This is the opposite of bcm43xx_chip_init() */
2679static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2680{
2681 bcm43xx_radio_turn_off(bcm);
2682 if (!modparam_noleds)
2683 bcm43xx_leds_exit(bcm);
2684 bcm43xx_gpio_cleanup(bcm);
2685 free_irq(bcm->irq, bcm);
2686 bcm43xx_release_firmware(bcm);
2687}
2688
2689/* Initialize the chip
2690 * http://bcm-specs.sipsolutions.net/ChipInit
2691 */
2692static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2693{
2694 int err;
2695 int iw_mode = bcm->ieee->iw_mode;
2696 int tmp;
2697 u32 value32;
2698 u16 value16;
2699
2700 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2701 BCM43xx_SBF_CORE_READY
2702 | BCM43xx_SBF_400);
2703
2704 err = bcm43xx_request_firmware(bcm);
2705 if (err)
2706 goto out;
2707 bcm43xx_upload_microcode(bcm);
2708
2709 err = bcm43xx_initialize_irq(bcm);
2710 if (err)
2711 goto out;
2712
2713 err = bcm43xx_gpio_init(bcm);
2714 if (err)
2715 goto err_free_irq;
2716
2717 bcm43xx_upload_initvals(bcm);
2718 bcm43xx_radio_turn_on(bcm);
2719
2720 if (modparam_noleds)
2721 bcm43xx_leds_turn_off(bcm);
2722 else
2723 bcm43xx_leds_update(bcm, 0);
2724
2725 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2726 err = bcm43xx_phy_init(bcm);
2727 if (err)
2728 goto err_radio_off;
2729
2730 /* Select initial Interference Mitigation. */
2731 tmp = bcm->current_core->radio->interfmode;
2732 bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2733 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2734
2735 bcm43xx_phy_set_antenna_diversity(bcm);
2736 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
2737 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
2738 value16 = bcm43xx_read16(bcm, 0x005E);
2739 value16 |= 0x0004;
2740 bcm43xx_write16(bcm, 0x005E, value16);
2741 }
2742 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2743 if (bcm->current_core->rev < 5)
2744 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2745
2746 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2747 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2748 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2749 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2750 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2751 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2752 /*FIXME: For now, use promiscuous mode at all times; otherwise we don't
2753 get broadcast or multicast packets */
2754 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2755 value32 |= BCM43xx_SBF_MODE_PROMISC;
2756 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2757
2758 if (iw_mode == IW_MODE_MONITOR) {
2759 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2760 value32 |= BCM43xx_SBF_MODE_PROMISC;
2761 value32 |= BCM43xx_SBF_MODE_MONITOR;
2762 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2763 }
2764 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2765 value32 |= 0x100000; //FIXME: What's this? Is this correct?
2766 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2767
2768 if (bcm->pio_mode) {
2769 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2770 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2771 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2772 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2773 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2774 }
2775
2776 /* Probe Response Timeout value */
2777 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2778 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2779
2780 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2781 if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3))
2782 bcm43xx_write16(bcm, 0x0612, 0x0064);
2783 else
2784 bcm43xx_write16(bcm, 0x0612, 0x0032);
2785 } else
2786 bcm43xx_write16(bcm, 0x0612, 0x0002);
2787
2788 if (bcm->current_core->rev < 3) {
2789 bcm43xx_write16(bcm, 0x060E, 0x0000);
2790 bcm43xx_write16(bcm, 0x0610, 0x8000);
2791 bcm43xx_write16(bcm, 0x0604, 0x0000);
2792 bcm43xx_write16(bcm, 0x0606, 0x0200);
2793 } else {
2794 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2795 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2796 }
2797 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2798 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2799 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2800 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2801 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2802
2803 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2804 value32 |= 0x00100000;
2805 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2806
2807 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2808
2809 assert(err == 0);
2810 dprintk(KERN_INFO PFX "Chip initialized\n");
2811out:
2812 return err;
2813
2814err_radio_off:
2815 bcm43xx_radio_turn_off(bcm);
2816 bcm43xx_gpio_cleanup(bcm);
2817err_free_irq:
2818 free_irq(bcm->irq, bcm);
2819 goto out;
2820}
2821
2822/* Validate chip access
2823 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2824static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2825{
2826 int err = -ENODEV;
2827 u32 value;
2828 u32 shm_backup;
2829
2830 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2831 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
2832 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) {
2833 printk(KERN_ERR PFX "Error: SHM mismatch (1) validating chip\n");
2834 goto out;
2835 }
2836
2837 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
2838 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) {
2839 printk(KERN_ERR PFX "Error: SHM mismatch (2) validating chip\n");
2840 goto out;
2841 }
2842
2843 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2844
2845 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2846 if ((value | 0x80000000) != 0x80000400) {
2847 printk(KERN_ERR PFX "Error: Bad Status Bitfield while validating chip\n");
2848 goto out;
2849 }
2850
2851 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2852 if (value != 0x00000000) {
2853 printk(KERN_ERR PFX "Error: Bad interrupt reason code while validating chip\n");
2854 goto out;
2855 }
2856
2857 err = 0;
2858out:
2859 return err;
2860}
2861
2862static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2863{
2864 int err, i;
2865 int current_core;
2866 u32 core_vendor, core_id, core_rev;
2867 u32 sb_id_hi, chip_id_32 = 0;
2868 u16 pci_device, chip_id_16;
2869 u8 core_count;
2870
2871 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2872 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
2873 memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo));
2874 memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo));
2875 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2876 * BCM43xx_MAX_80211_CORES);
2877
2878 memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo)
2879 * BCM43xx_MAX_80211_CORES);
2880 memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo)
2881 * BCM43xx_MAX_80211_CORES);
2882
2883 /* map core 0 */
2884 err = _switch_core(bcm, 0);
2885 if (err)
2886 goto out;
2887
2888 /* fetch sb_id_hi from core information registers */
2889 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2890
2891 core_id = (sb_id_hi & 0xFFF0) >> 4;
2892 core_rev = (sb_id_hi & 0xF);
2893 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2894
2895 /* if present, chipcommon is always core 0; read the chipid from it */
2896 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2897 chip_id_32 = bcm43xx_read32(bcm, 0);
2898 chip_id_16 = chip_id_32 & 0xFFFF;
2899 bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE;
2900 bcm->core_chipcommon.id = core_id;
2901 bcm->core_chipcommon.rev = core_rev;
2902 bcm->core_chipcommon.index = 0;
2903 /* While we are at it, also read the capabilities. */
2904 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2905 } else {
2906 /* without a chipCommon, use a hard coded table. */
2907 pci_device = bcm->pci_dev->device;
2908 if (pci_device == 0x4301)
2909 chip_id_16 = 0x4301;
2910 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2911 chip_id_16 = 0x4307;
2912 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2913 chip_id_16 = 0x4402;
2914 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2915 chip_id_16 = 0x4610;
2916 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2917 chip_id_16 = 0x4710;
2918#ifdef CONFIG_BCM947XX
2919 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2920 chip_id_16 = 0x4309;
2921#endif
2922 else {
2923 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2924 return -ENODEV;
2925 }
2926 }
2927
2928 /* ChipCommon with Core Rev >=4 encodes number of cores,
2929 * otherwise consult hardcoded table */
2930 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2931 core_count = (chip_id_32 & 0x0F000000) >> 24;
2932 } else {
2933 switch (chip_id_16) {
2934 case 0x4610:
2935 case 0x4704:
2936 case 0x4710:
2937 core_count = 9;
2938 break;
2939 case 0x4310:
2940 core_count = 8;
2941 break;
2942 case 0x5365:
2943 core_count = 7;
2944 break;
2945 case 0x4306:
2946 core_count = 6;
2947 break;
2948 case 0x4301:
2949 case 0x4307:
2950 core_count = 5;
2951 break;
2952 case 0x4402:
2953 core_count = 3;
2954 break;
2955 default:
2956 /* SOL if we get here */
2957 assert(0);
2958 core_count = 1;
2959 }
2960 }
2961
2962 bcm->chip_id = chip_id_16;
2963 bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16;
2964
2965 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2966 bcm->chip_id, bcm->chip_rev);
2967 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
2968 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) {
2969 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2970 core_id, core_rev, core_vendor,
2971 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2972 }
2973
2974 if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE)
2975 current_core = 1;
2976 else
2977 current_core = 0;
2978 for ( ; current_core < core_count; current_core++) {
2979 struct bcm43xx_coreinfo *core;
2980
2981 err = _switch_core(bcm, current_core);
2982 if (err)
2983 goto out;
2984 /* Gather information */
2985 /* fetch sb_id_hi from core information registers */
2986 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2987
2988 /* extract core_id, core_rev, core_vendor */
2989 core_id = (sb_id_hi & 0xFFF0) >> 4;
2990 core_rev = (sb_id_hi & 0xF);
2991 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2992
2993 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2994 current_core, core_id, core_rev, core_vendor,
2995 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2996
2997 core = NULL;
2998 switch (core_id) {
2999 case BCM43xx_COREID_PCI:
3000 core = &bcm->core_pci;
3001 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
3002 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
3003 continue;
3004 }
3005 break;
3006 case BCM43xx_COREID_V90:
3007 core = &bcm->core_v90;
3008 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
3009 printk(KERN_WARNING PFX "Multiple V90 cores found.\n");
3010 continue;
3011 }
3012 break;
3013 case BCM43xx_COREID_PCMCIA:
3014 core = &bcm->core_pcmcia;
3015 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
3016 printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n");
3017 continue;
3018 }
3019 break;
3020 case BCM43xx_COREID_ETHERNET:
3021 core = &bcm->core_ethernet;
3022 if (core->flags & BCM43xx_COREFLAG_AVAILABLE) {
3023 printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n");
3024 continue;
3025 }
3026 break;
3027 case BCM43xx_COREID_80211:
3028 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3029 core = &(bcm->core_80211[i]);
3030 if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE))
3031 break;
3032 core = NULL;
3033 }
3034 if (!core) {
3035 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
3036 BCM43xx_MAX_80211_CORES);
3037 continue;
3038 }
3039 if (i != 0) {
3040 /* More than one 80211 core is only supported
3041 * by special chips.
3042 * There are chips with two 80211 cores, but with
3043 * dangling pins on the second core. Be careful
3044 * and ignore these cores here.
3045 */
3046 if (bcm->pci_dev->device != 0x4324) {
3047 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
3048 continue;
3049 }
3050 }
3051 switch (core_rev) {
3052 case 2:
3053 case 4:
3054 case 5:
3055 case 6:
3056 case 7:
3057 case 9:
3058 break;
3059 default:
3060 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
3061 core_rev);
3062 err = -ENODEV;
3063 goto out;
3064 }
3065 core->phy = &bcm->phy[i];
3066 core->phy->antenna_diversity = 0xffff;
3067 core->phy->savedpctlreg = 0xFFFF;
3068 core->phy->minlowsig[0] = 0xFFFF;
3069 core->phy->minlowsig[1] = 0xFFFF;
3070 core->phy->minlowsigpos[0] = 0;
3071 core->phy->minlowsigpos[1] = 0;
3072 spin_lock_init(&core->phy->lock);
3073 core->radio = &bcm->radio[i];
3074 core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
3075 core->radio->channel = 0xFF;
3076 core->radio->initial_channel = 0xFF;
3077 core->radio->lofcal = 0xFFFF;
3078 core->radio->initval = 0xFFFF;
3079 core->radio->nrssi[0] = -1000;
3080 core->radio->nrssi[1] = -1000;
3081 core->dma = &bcm->dma[i];
3082 core->pio = &bcm->pio[i];
3083 break;
3084 case BCM43xx_COREID_CHIPCOMMON:
3085 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
3086 break;
3087 default:
3088 printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id);
3089 }
3090 if (core) {
3091 core->flags |= BCM43xx_COREFLAG_AVAILABLE;
3092 core->id = core_id;
3093 core->rev = core_rev;
3094 core->index = current_core;
3095 }
3096 }
3097
3098 if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) {
3099 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
3100 err = -ENODEV;
3101 goto out;
3102 }
3103
3104 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3105
3106 assert(err == 0);
3107out:
3108 return err;
3109}
3110
3111static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
3112{
3113 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
3114 u8 *bssid = bcm->ieee->bssid;
3115
3116 switch (bcm->ieee->iw_mode) {
3117 case IW_MODE_ADHOC:
3118 random_ether_addr(bssid);
3119 break;
3120 case IW_MODE_MASTER:
3121 case IW_MODE_INFRA:
3122 case IW_MODE_REPEAT:
3123 case IW_MODE_SECOND:
3124 case IW_MODE_MONITOR:
3125 memcpy(bssid, mac, ETH_ALEN);
3126 break;
3127 default:
3128 assert(0);
3129 }
3130}
3131
3132static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
3133 u16 rate,
3134 int is_ofdm)
3135{
3136 u16 offset;
3137
3138 if (is_ofdm) {
3139 offset = 0x480;
3140 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
3141 }
3142 else {
3143 offset = 0x4C0;
3144 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
3145 }
3146 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
3147 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
3148}
3149
3150static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
3151{
3152 switch (bcm->current_core->phy->type) {
3153 case BCM43xx_PHYTYPE_A:
3154 case BCM43xx_PHYTYPE_G:
3155 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
3156 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
3157 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
3158 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
3159 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
3160 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
3161 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
3162 case BCM43xx_PHYTYPE_B:
3163 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
3164 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
3165 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
3166 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
3167 break;
3168 default:
3169 assert(0);
3170 }
3171}
3172
3173static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
3174{
3175 bcm43xx_chip_cleanup(bcm);
3176 bcm43xx_pio_free(bcm);
3177 bcm43xx_dma_free(bcm);
3178
3179 bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED;
3180}
3181
3182/* http://bcm-specs.sipsolutions.net/80211Init */
3183static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
3184{
3185 u32 ucodeflags;
3186 int err;
3187 u32 sbimconfiglow;
3188 u8 limit;
3189
3190 if (bcm->chip_rev < 5) {
3191 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3192 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3193 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3194 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
3195 sbimconfiglow |= 0x32;
3196 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
3197 sbimconfiglow |= 0x53;
3198 else
3199 assert(0);
3200 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
3201 }
3202
3203 bcm43xx_phy_calibrate(bcm);
3204 err = bcm43xx_chip_init(bcm);
3205 if (err)
3206 goto out;
3207
3208 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
3209 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
3210
3211 if (0 /*FIXME: which condition has to be used here? */)
3212 ucodeflags |= 0x00000010;
3213
3214 /* HW decryption needs to be set now */
3215 ucodeflags |= 0x40000000;
3216
3217 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
3218 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
3219 if (bcm->current_core->phy->rev == 1)
3220 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
3221 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
3222 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
3223 } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) {
3224 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
3225 if ((bcm->current_core->phy->rev >= 2) &&
3226 (bcm->current_core->radio->version == 0x2050))
3227 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
3228 }
3229
3230 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
3231 BCM43xx_UCODEFLAGS_OFFSET)) {
3232 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
3233 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
3234 }
3235
3236 /* Short/Long Retry Limit.
3237 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
3238 * the chip-internal counter.
3239 */
3240 limit = limit_value(modparam_short_retry, 0, 0xF);
3241 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
3242 limit = limit_value(modparam_long_retry, 0, 0xF);
3243 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
3244
3245 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
3246 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
3247
3248 bcm43xx_rate_memory_init(bcm);
3249
3250 /* Minimum Contention Window */
3251 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B)
3252 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
3253 else
3254 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
3255 /* Maximum Contention Window */
3256 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
3257
3258 bcm43xx_gen_bssid(bcm);
3259 bcm43xx_write_mac_bssid_templates(bcm);
3260
3261 if (bcm->current_core->rev >= 5)
3262 bcm43xx_write16(bcm, 0x043C, 0x000C);
3263
3264 if (!bcm->pio_mode) {
3265 err = bcm43xx_dma_init(bcm);
3266 if (err)
3267 goto err_chip_cleanup;
3268 } else {
3269 err = bcm43xx_pio_init(bcm);
3270 if (err)
3271 goto err_chip_cleanup;
3272 }
3273 bcm43xx_write16(bcm, 0x0612, 0x0050);
3274 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
3275 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
3276
3277 bcm43xx_mac_enable(bcm);
3278 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
3279
3280 bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED;
3281out:
3282 return err;
3283
3284err_chip_cleanup:
3285 bcm43xx_chip_cleanup(bcm);
3286 goto out;
3287}
3288
3289static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
3290{
3291 int err;
3292 u16 pci_status;
3293
3294 err = bcm43xx_pctl_set_crystal(bcm, 1);
3295 if (err)
3296 goto out;
3297 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
3298 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
3299
3300out:
3301 return err;
3302}
3303
3304static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
3305{
3306 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
3307 bcm43xx_pctl_set_crystal(bcm, 0);
3308}
3309
3310static inline void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
3311 u32 address,
3312 u32 data)
3313{
3314 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
3315 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
3316}
3317
3318static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
3319{
3320 int err;
3321 struct bcm43xx_coreinfo *old_core;
3322
3323 old_core = bcm->current_core;
3324 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
3325 if (err)
3326 goto out;
3327
3328 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
3329
3330 bcm43xx_switch_core(bcm, old_core);
3331 assert(err == 0);
3332out:
3333 return err;
3334}
3335
3336/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
3337 * To enable core 0, pass a core_mask of 1<<0
3338 */
3339static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
3340 u32 core_mask)
3341{
3342 u32 backplane_flag_nr;
3343 u32 value;
3344 struct bcm43xx_coreinfo *old_core;
3345 int err = 0;
3346
3347 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
3348 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
3349
3350 old_core = bcm->current_core;
3351 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
3352 if (err)
3353 goto out;
3354
3355 if (bcm->core_pci.rev < 6) {
3356 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
3357 value |= (1 << backplane_flag_nr);
3358 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
3359 } else {
3360 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
3361 if (err) {
3362 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3363 goto out_switch_back;
3364 }
3365 value |= core_mask << 8;
3366 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3367 if (err) {
3368 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3369 goto out_switch_back;
3370 }
3371 }
3372
3373 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3374 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3375 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3376
3377 if (bcm->core_pci.rev < 5) {
3378 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3379 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3380 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3381 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3382 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3383 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3384 err = bcm43xx_pcicore_commit_settings(bcm);
3385 assert(err == 0);
3386 }
3387
3388out_switch_back:
3389 err = bcm43xx_switch_core(bcm, old_core);
3390out:
3391 return err;
3392}
3393
3394static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3395{
3396 ieee80211softmac_start(bcm->net_dev);
3397}
3398
3399static void bcm43xx_periodic_work0_handler(void *d)
3400{
3401 struct bcm43xx_private *bcm = d;
3402 unsigned long flags;
3403 //TODO: unsigned int aci_average;
3404
3405 spin_lock_irqsave(&bcm->lock, flags);
3406
3407 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
3408 //FIXME: aci_average = bcm43xx_update_aci_average(bcm);
3409 if (bcm->current_core->radio->aci_enable && bcm->current_core->radio->aci_wlan_automatic) {
3410 bcm43xx_mac_suspend(bcm);
3411 if (!bcm->current_core->radio->aci_enable &&
3412 1 /*FIXME: We are not scanning? */) {
3413 /*FIXME: First add bcm43xx_update_aci_average() before
3414 * uncommenting this: */
3415 //if (bcm43xx_radio_aci_scan)
3416 // bcm43xx_radio_set_interference_mitigation(bcm,
3417 // BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3418 } else if (1/*FIXME*/) {
3419 //if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm)))
3420 // bcm43xx_radio_set_interference_mitigation(bcm,
3421 // BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3422 }
3423 bcm43xx_mac_enable(bcm);
3424 } else if (bcm->current_core->radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) {
3425 if (bcm->current_core->phy->rev == 1) {
3426 //FIXME: implement rev1 workaround
3427 }
3428 }
3429 }
3430 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3431 //TODO for APHY (temperature?)
3432
3433 if (likely(!bcm->shutting_down)) {
3434 queue_delayed_work(bcm->workqueue, &bcm->periodic_work0,
3435 BCM43xx_PERIODIC_0_DELAY);
3436 }
3437 spin_unlock_irqrestore(&bcm->lock, flags);
3438}
3439
3440static void bcm43xx_periodic_work1_handler(void *d)
3441{
3442 struct bcm43xx_private *bcm = d;
3443 unsigned long flags;
3444
3445 spin_lock_irqsave(&bcm->lock, flags);
3446
3447 bcm43xx_phy_lo_mark_all_unused(bcm);
3448 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3449 bcm43xx_mac_suspend(bcm);
3450 bcm43xx_calc_nrssi_slope(bcm);
3451 bcm43xx_mac_enable(bcm);
3452 }
3453
3454 if (likely(!bcm->shutting_down)) {
3455 queue_delayed_work(bcm->workqueue, &bcm->periodic_work1,
3456 BCM43xx_PERIODIC_1_DELAY);
3457 }
3458 spin_unlock_irqrestore(&bcm->lock, flags);
3459}
3460
3461static void bcm43xx_periodic_work2_handler(void *d)
3462{
3463 struct bcm43xx_private *bcm = d;
3464 unsigned long flags;
3465
3466 spin_lock_irqsave(&bcm->lock, flags);
3467
3468 assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_G);
3469 assert(bcm->current_core->phy->rev >= 2);
3470
3471 bcm43xx_mac_suspend(bcm);
3472 bcm43xx_phy_lo_g_measure(bcm);
3473 bcm43xx_mac_enable(bcm);
3474
3475 if (likely(!bcm->shutting_down)) {
3476 queue_delayed_work(bcm->workqueue, &bcm->periodic_work2,
3477 BCM43xx_PERIODIC_2_DELAY);
3478 }
3479 spin_unlock_irqrestore(&bcm->lock, flags);
3480}
3481
3482static void bcm43xx_periodic_work3_handler(void *d)
3483{
3484 struct bcm43xx_private *bcm = d;
3485 unsigned long flags;
3486
3487 spin_lock_irqsave(&bcm->lock, flags);
3488
3489 /* Update device statistics. */
3490 bcm43xx_calculate_link_quality(bcm);
3491
3492 if (likely(!bcm->shutting_down)) {
3493 queue_delayed_work(bcm->workqueue, &bcm->periodic_work3,
3494 BCM43xx_PERIODIC_3_DELAY);
3495 }
3496 spin_unlock_irqrestore(&bcm->lock, flags);
3497}
3498
3499/* Delete all periodic tasks and make
3500 * sure they are not running any longer
3501 */
3502static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3503{
3504 cancel_delayed_work(&bcm->periodic_work0);
3505 cancel_delayed_work(&bcm->periodic_work1);
3506 cancel_delayed_work(&bcm->periodic_work2);
3507 cancel_delayed_work(&bcm->periodic_work3);
3508 flush_workqueue(bcm->workqueue);
3509}
3510
3511/* Setup all periodic tasks. */
3512static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3513{
3514 INIT_WORK(&bcm->periodic_work0, bcm43xx_periodic_work0_handler, bcm);
3515 INIT_WORK(&bcm->periodic_work1, bcm43xx_periodic_work1_handler, bcm);
3516 INIT_WORK(&bcm->periodic_work2, bcm43xx_periodic_work2_handler, bcm);
3517 INIT_WORK(&bcm->periodic_work3, bcm43xx_periodic_work3_handler, bcm);
3518
3519 /* Periodic task 0: Delay ~15sec */
3520 queue_delayed_work(bcm->workqueue, &bcm->periodic_work0,
3521 BCM43xx_PERIODIC_0_DELAY);
3522
3523 /* Periodic task 1: Delay ~60sec */
3524 queue_delayed_work(bcm->workqueue, &bcm->periodic_work1,
3525 BCM43xx_PERIODIC_1_DELAY);
3526
3527 /* Periodic task 2: Delay ~120sec */
3528 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
3529 bcm->current_core->phy->rev >= 2) {
3530 queue_delayed_work(bcm->workqueue, &bcm->periodic_work2,
3531 BCM43xx_PERIODIC_2_DELAY);
3532 }
3533
3534 /* Periodic task 3: Delay ~30sec */
3535 queue_delayed_work(bcm->workqueue, &bcm->periodic_work3,
3536 BCM43xx_PERIODIC_3_DELAY);
3537}
3538
3539static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3540{
3541 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3542 0x0056) * 2;
3543 bcm43xx_clear_keys(bcm);
3544}
3545
3546/* This is the opposite of bcm43xx_init_board() */
3547static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3548{
3549 int i, err;
3550 unsigned long flags;
3551
3552 spin_lock_irqsave(&bcm->lock, flags);
3553 bcm->initialized = 0;
3554 bcm->shutting_down = 1;
3555 spin_unlock_irqrestore(&bcm->lock, flags);
3556
3557 bcm43xx_periodic_tasks_delete(bcm);
3558
3559 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3560 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE))
3561 continue;
3562 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3563 continue;
3564
3565 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3566 assert(err == 0);
3567 bcm43xx_wireless_core_cleanup(bcm);
3568 }
3569
3570 bcm43xx_pctl_set_crystal(bcm, 0);
3571
3572 spin_lock_irqsave(&bcm->lock, flags);
3573 bcm->shutting_down = 0;
3574 spin_unlock_irqrestore(&bcm->lock, flags);
3575}
3576
3577static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3578{
3579 int i, err;
3580 int num_80211_cores;
3581 int connect_phy;
3582 unsigned long flags;
3583
3584 might_sleep();
3585
3586 spin_lock_irqsave(&bcm->lock, flags);
3587 bcm->initialized = 0;
3588 bcm->shutting_down = 0;
3589 spin_unlock_irqrestore(&bcm->lock, flags);
3590
3591 err = bcm43xx_pctl_set_crystal(bcm, 1);
3592 if (err)
3593 goto out;
3594 err = bcm43xx_pctl_init(bcm);
3595 if (err)
3596 goto err_crystal_off;
3597 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3598 if (err)
3599 goto err_crystal_off;
3600
3601 tasklet_enable(&bcm->isr_tasklet);
3602 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3603 for (i = 0; i < num_80211_cores; i++) {
3604 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3605 assert(err != -ENODEV);
3606 if (err)
3607 goto err_80211_unwind;
3608
3609 /* Enable the selected wireless core.
3610 * Connect PHY only on the first core.
3611 */
3612 if (!bcm43xx_core_enabled(bcm)) {
3613 if (num_80211_cores == 1) {
3614 connect_phy = bcm->current_core->phy->connected;
3615 } else {
3616 if (i == 0)
3617 connect_phy = 1;
3618 else
3619 connect_phy = 0;
3620 }
3621 bcm43xx_wireless_core_reset(bcm, connect_phy);
3622 }
3623
3624 if (i != 0)
3625 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3626
3627 err = bcm43xx_wireless_core_init(bcm);
3628 if (err)
3629 goto err_80211_unwind;
3630
3631 if (i != 0) {
3632 bcm43xx_mac_suspend(bcm);
3633 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3634 bcm43xx_radio_turn_off(bcm);
3635 }
3636 }
3637 bcm->active_80211_core = &bcm->core_80211[0];
3638 if (num_80211_cores >= 2) {
3639 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3640 bcm43xx_mac_enable(bcm);
3641 }
3642 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3643 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3644 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3645 bcm43xx_security_init(bcm);
3646 bcm43xx_softmac_init(bcm);
3647
3648 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3649
3650 spin_lock_irqsave(&bcm->lock, flags);
3651 bcm->initialized = 1;
3652 spin_unlock_irqrestore(&bcm->lock, flags);
3653
3654 if (bcm->current_core->radio->initial_channel != 0xFF) {
3655 bcm43xx_mac_suspend(bcm);
3656 bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0);
3657 bcm43xx_mac_enable(bcm);
3658 }
3659 bcm43xx_periodic_tasks_setup(bcm);
3660
3661 assert(err == 0);
3662out:
3663 return err;
3664
3665err_80211_unwind:
3666 tasklet_disable(&bcm->isr_tasklet);
3667 /* unwind all 80211 initialization */
3668 for (i = 0; i < num_80211_cores; i++) {
3669 if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED))
3670 continue;
3671 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3672 bcm43xx_wireless_core_cleanup(bcm);
3673 }
3674err_crystal_off:
3675 bcm43xx_pctl_set_crystal(bcm, 0);
3676 goto out;
3677}
3678
3679static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3680{
3681 struct pci_dev *pci_dev = bcm->pci_dev;
3682 int i;
3683
3684 bcm43xx_chipset_detach(bcm);
3685 /* Do _not_ access the chip, after it is detached. */
3686 iounmap(bcm->mmio_addr);
3687
3688 pci_release_regions(pci_dev);
3689 pci_disable_device(pci_dev);
3690
3691 /* Free allocated structures/fields */
3692 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3693 kfree(bcm->phy[i]._lo_pairs);
3694 if (bcm->phy[i].dyn_tssi_tbl)
3695 kfree(bcm->phy[i].tssi2dbm);
3696 }
3697}
3698
3699static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3700{
3701 u16 value;
3702 u8 phy_version;
3703 u8 phy_type;
3704 u8 phy_rev;
3705 int phy_rev_ok = 1;
3706 void *p;
3707
3708 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3709
3710 phy_version = (value & 0xF000) >> 12;
3711 phy_type = (value & 0x0F00) >> 8;
3712 phy_rev = (value & 0x000F);
3713
3714 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3715 phy_version, phy_type, phy_rev);
3716
3717 switch (phy_type) {
3718 case BCM43xx_PHYTYPE_A:
3719 if (phy_rev >= 4)
3720 phy_rev_ok = 0;
3721 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3722 * if we switch 80211 cores after init is done.
3723 * As we do not implement on the fly switching between
3724 * wireless cores, I will leave this as a future task.
3725 */
3726 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3727 bcm->ieee->mode = IEEE_A;
3728 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3729 IEEE80211_24GHZ_BAND;
3730 break;
3731 case BCM43xx_PHYTYPE_B:
3732 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3733 phy_rev_ok = 0;
3734 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3735 bcm->ieee->mode = IEEE_B;
3736 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3737 break;
3738 case BCM43xx_PHYTYPE_G:
3739 if (phy_rev > 7)
3740 phy_rev_ok = 0;
3741 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3742 IEEE80211_CCK_MODULATION;
3743 bcm->ieee->mode = IEEE_G;
3744 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3745 break;
3746 default:
3747 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3748 phy_type);
3749 return -ENODEV;
3750 };
3751 if (!phy_rev_ok) {
3752 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3753 phy_rev);
3754 }
3755
3756 bcm->current_core->phy->version = phy_version;
3757 bcm->current_core->phy->type = phy_type;
3758 bcm->current_core->phy->rev = phy_rev;
3759 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3760 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3761 GFP_KERNEL);
3762 if (!p)
3763 return -ENOMEM;
3764 bcm->current_core->phy->_lo_pairs = p;
3765 }
3766
3767 return 0;
3768}
3769
3770static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3771{
3772 struct pci_dev *pci_dev = bcm->pci_dev;
3773 struct net_device *net_dev = bcm->net_dev;
3774 int err;
3775 int i;
3776 void __iomem *ioaddr;
3777 unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
3778 int num_80211_cores;
3779 u32 coremask;
3780
3781 err = pci_enable_device(pci_dev);
3782 if (err) {
3783 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
3784 err = -ENODEV;
3785 goto out;
3786 }
3787
3788 mmio_start = pci_resource_start(pci_dev, 0);
3789 mmio_end = pci_resource_end(pci_dev, 0);
3790 mmio_flags = pci_resource_flags(pci_dev, 0);
3791 mmio_len = pci_resource_len(pci_dev, 0);
3792
3793 /* make sure PCI base addr is MMIO */
3794 if (!(mmio_flags & IORESOURCE_MEM)) {
3795 printk(KERN_ERR PFX
3796 "%s, region #0 not an MMIO resource, aborting\n",
3797 pci_name(pci_dev));
3798 err = -ENODEV;
3799 goto err_pci_disable;
3800 }
3801//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there?
3802#ifndef CONFIG_BCM947XX
3803 if (mmio_len != BCM43xx_IO_SIZE) {
3804 printk(KERN_ERR PFX
3805 "%s: invalid PCI mem region size(s), aborting\n",
3806 pci_name(pci_dev));
3807 err = -ENODEV;
3808 goto err_pci_disable;
3809 }
3810#endif
3811
3812 err = pci_request_regions(pci_dev, DRV_NAME);
3813 if (err) {
3814 printk(KERN_ERR PFX
3815 "could not access PCI resources (%i)\n", err);
3816 goto err_pci_disable;
3817 }
3818
3819 /* enable PCI bus-mastering */
3820 pci_set_master(pci_dev);
3821
3822 /* ioremap MMIO region */
3823 ioaddr = ioremap(mmio_start, mmio_len);
3824 if (!ioaddr) {
3825 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3826 pci_name(pci_dev));
3827 err = -EIO;
3828 goto err_pci_release;
3829 }
3830
3831 net_dev->base_addr = (unsigned long)ioaddr;
3832 bcm->mmio_addr = ioaddr;
3833 bcm->mmio_len = mmio_len;
3834
3835 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3836 &bcm->board_vendor);
3837 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3838 &bcm->board_type);
3839 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3840 &bcm->board_revision);
3841
3842 err = bcm43xx_chipset_attach(bcm);
3843 if (err)
3844 goto err_iounmap;
3845 err = bcm43xx_pctl_init(bcm);
3846 if (err)
3847 goto err_chipset_detach;
3848 err = bcm43xx_probe_cores(bcm);
3849 if (err)
3850 goto err_chipset_detach;
3851
3852 num_80211_cores = bcm43xx_num_80211_cores(bcm);
3853
3854 /* Attach all IO cores to the backplane. */
3855 coremask = 0;
3856 for (i = 0; i < num_80211_cores; i++)
3857 coremask |= (1 << bcm->core_80211[i].index);
3858 //FIXME: Also attach some non80211 cores?
3859 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3860 if (err) {
3861 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3862 goto err_chipset_detach;
3863 }
3864
3865 err = bcm43xx_read_sprom(bcm);
3866 if (err)
3867 goto err_chipset_detach;
3868 err = bcm43xx_leds_init(bcm);
3869 if (err)
3870 goto err_chipset_detach;
3871
3872 for (i = 0; i < num_80211_cores; i++) {
3873 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3874 assert(err != -ENODEV);
3875 if (err)
3876 goto err_80211_unwind;
3877
3878 /* Enable the selected wireless core.
3879 * Connect PHY only on the first core.
3880 */
3881 bcm43xx_wireless_core_reset(bcm, (i == 0));
3882
3883 err = bcm43xx_read_phyinfo(bcm);
3884 if (err && (i == 0))
3885 goto err_80211_unwind;
3886
3887 err = bcm43xx_read_radioinfo(bcm);
3888 if (err && (i == 0))
3889 goto err_80211_unwind;
3890
3891 err = bcm43xx_validate_chip(bcm);
3892 if (err && (i == 0))
3893 goto err_80211_unwind;
3894
3895 bcm43xx_radio_turn_off(bcm);
3896 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3897 if (err)
3898 goto err_80211_unwind;
3899 bcm43xx_wireless_core_disable(bcm);
3900 }
3901 bcm43xx_pctl_set_crystal(bcm, 0);
3902
3903 /* Set the MAC address in the networking subsystem */
3904 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
3905 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3906 else
3907 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3908
3909 bcm43xx_geo_init(bcm);
3910
3911 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3912 "Broadcom %04X", bcm->chip_id);
3913
3914 assert(err == 0);
3915out:
3916 return err;
3917
3918err_80211_unwind:
3919 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3920 kfree(bcm->phy[i]._lo_pairs);
3921 if (bcm->phy[i].dyn_tssi_tbl)
3922 kfree(bcm->phy[i].tssi2dbm);
3923 }
3924err_chipset_detach:
3925 bcm43xx_chipset_detach(bcm);
3926err_iounmap:
3927 iounmap(bcm->mmio_addr);
3928err_pci_release:
3929 pci_release_regions(pci_dev);
3930err_pci_disable:
3931 pci_disable_device(pci_dev);
3932 goto out;
3933}
3934
3935static inline
3936s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi,
3937 int ofdm, int adjust_2053, int adjust_2050)
3938{
3939 s32 tmp;
3940
3941 switch (bcm->current_core->radio->version) {
3942 case 0x2050:
3943 if (ofdm) {
3944 tmp = in_rssi;
3945 if (tmp > 127)
3946 tmp -= 256;
3947 tmp *= 73;
3948 tmp /= 64;
3949 if (adjust_2050)
3950 tmp += 25;
3951 else
3952 tmp -= 3;
3953 } else {
3954 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3955 if (in_rssi > 63)
3956 in_rssi = 63;
3957 tmp = bcm->current_core->radio->nrssi_lt[in_rssi];
3958 tmp = 31 - tmp;
3959 tmp *= -131;
3960 tmp /= 128;
3961 tmp -= 57;
3962 } else {
3963 tmp = in_rssi;
3964 tmp = 31 - tmp;
3965 tmp *= -149;
3966 tmp /= 128;
3967 tmp -= 68;
3968 }
3969 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
3970 adjust_2050)
3971 tmp += 25;
3972 }
3973 break;
3974 case 0x2060:
3975 if (in_rssi > 127)
3976 tmp = in_rssi - 256;
3977 else
3978 tmp = in_rssi;
3979 break;
3980 default:
3981 tmp = in_rssi;
3982 tmp -= 11;
3983 tmp *= 103;
3984 tmp /= 64;
3985 if (adjust_2053)
3986 tmp -= 109;
3987 else
3988 tmp -= 83;
3989 }
3990
3991 return (s8)tmp;
3992}
3993
3994static inline
3995s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi)
3996{
3997 s8 ret;
3998
3999 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) {
4000 //TODO: Incomplete specs.
4001 ret = 0;
4002 } else
4003 ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
4004
4005 return ret;
4006}
4007
4008static inline
4009int bcm43xx_rx_packet(struct bcm43xx_private *bcm,
4010 struct sk_buff *skb,
4011 struct ieee80211_rx_stats *stats)
4012{
4013 int err;
4014
4015 err = ieee80211_rx(bcm->ieee, skb, stats);
4016 if (unlikely(err == 0))
4017 return -EINVAL;
4018 return 0;
4019}
4020
4021int fastcall bcm43xx_rx(struct bcm43xx_private *bcm,
4022 struct sk_buff *skb,
4023 struct bcm43xx_rxhdr *rxhdr)
4024{
4025 struct bcm43xx_plcp_hdr4 *plcp;
4026 struct ieee80211_rx_stats stats;
4027 struct ieee80211_hdr_4addr *wlhdr;
4028 u16 frame_ctl;
4029 int is_packet_for_us = 0;
4030 int err = -EINVAL;
4031 const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
4032 const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
4033 const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
4034 const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
4035
4036 if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
4037 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
4038 /* Skip two unknown bytes and the PLCP header. */
4039 skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
4040 } else {
4041 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
4042 /* Skip the PLCP header. */
4043 skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
4044 }
4045 /* The SKB contains the PAYLOAD (wireless header + data)
4046 * at this point. The FCS at the end is stripped.
4047 */
4048
4049 memset(&stats, 0, sizeof(stats));
4050 stats.mac_time = le16_to_cpu(rxhdr->mactime);
4051 stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
4052 !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
4053 !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
4054 stats.signal = rxhdr->signal_quality; //FIXME
4055//TODO stats.noise =
4056 stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm);
4057//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
4058 stats.received_channel = bcm->current_core->radio->channel;
4059//TODO stats.control =
4060 stats.mask = IEEE80211_STATMASK_SIGNAL |
4061//TODO IEEE80211_STATMASK_NOISE |
4062 IEEE80211_STATMASK_RATE |
4063 IEEE80211_STATMASK_RSSI;
4064 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
4065 stats.freq = IEEE80211_52GHZ_BAND;
4066 else
4067 stats.freq = IEEE80211_24GHZ_BAND;
4068 stats.len = skb->len;
4069
4070 bcm->stats.last_rx = jiffies;
4071 if (bcm->ieee->iw_mode == IW_MODE_MONITOR)
4072 return bcm43xx_rx_packet(bcm, skb, &stats);
4073
4074 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
4075
4076 switch (bcm->ieee->iw_mode) {
4077 case IW_MODE_ADHOC:
4078 if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
4079 memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
4080 is_broadcast_ether_addr(wlhdr->addr1) ||
4081 is_multicast_ether_addr(wlhdr->addr1) ||
4082 bcm->net_dev->flags & IFF_PROMISC)
4083 is_packet_for_us = 1;
4084 break;
4085 case IW_MODE_INFRA:
4086 default:
4087 /* When receiving multicast or broadcast packets, filter out
4088 the packets we send ourself; we shouldn't see those */
4089 if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
4090 memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
4091 (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
4092 (is_broadcast_ether_addr(wlhdr->addr1) ||
4093 is_multicast_ether_addr(wlhdr->addr1) ||
4094 bcm->net_dev->flags & IFF_PROMISC)))
4095 is_packet_for_us = 1;
4096 break;
4097 }
4098
4099 frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
4100
4101 if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
4102 frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
4103 wlhdr->frame_ctl = cpu_to_le16(frame_ctl);
4104 /* trim IV and ICV */
4105 /* FIXME: this must be done only for WEP encrypted packets */
4106 if (skb->len < 32) {
4107 dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
4108 "set and length < 32)\n");
4109 return -EINVAL;
4110 } else {
4111 memmove(skb->data + 4, skb->data, 24);
4112 skb_pull(skb, 4);
4113 skb_trim(skb, skb->len - 4);
4114 stats.len -= 8;
4115 }
4116 /* do _not_ use wlhdr again without reassigning it */
4117 }
4118
4119 switch (WLAN_FC_GET_TYPE(frame_ctl)) {
4120 case IEEE80211_FTYPE_MGMT:
4121 ieee80211_rx_mgt(bcm->ieee, skb->data, &stats);
4122 break;
4123 case IEEE80211_FTYPE_DATA:
4124 if (is_packet_for_us)
4125 err = bcm43xx_rx_packet(bcm, skb, &stats);
4126 break;
4127 case IEEE80211_FTYPE_CTL:
4128 break;
4129 default:
4130 assert(0);
4131 return -EINVAL;
4132 }
4133
4134 return err;
4135}
4136
4137/* Do the Hardware IO operations to send the txb */
4138static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
4139 struct ieee80211_txb *txb)
4140{
4141 int err = -ENODEV;
4142
4143 if (bcm->pio_mode)
4144 err = bcm43xx_pio_transfer_txb(bcm, txb);
4145 else
4146 err = bcm43xx_dma_transfer_txb(bcm, txb);
4147
4148 return err;
4149}
4150
4151static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
4152 u8 channel)
4153{
4154 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4155 unsigned long flags;
4156
4157 spin_lock_irqsave(&bcm->lock, flags);
4158 bcm43xx_mac_suspend(bcm);
4159 bcm43xx_radio_selectchannel(bcm, channel, 0);
4160 bcm43xx_mac_enable(bcm);
4161 spin_unlock_irqrestore(&bcm->lock, flags);
4162}
4163
4164/* set_security() callback in struct ieee80211_device */
4165static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
4166 struct ieee80211_security *sec)
4167{
4168 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4169 struct ieee80211_security *secinfo = &bcm->ieee->sec;
4170 unsigned long flags;
4171 int keyidx;
4172
4173 dprintk(KERN_INFO PFX "set security called\n");
4174
4175 spin_lock_irqsave(&bcm->lock, flags);
4176
4177 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
4178 if (sec->flags & (1<<keyidx)) {
4179 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
4180 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
4181 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
4182 }
4183
4184 if (sec->flags & SEC_ACTIVE_KEY) {
4185 secinfo->active_key = sec->active_key;
4186 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
4187 }
4188 if (sec->flags & SEC_UNICAST_GROUP) {
4189 secinfo->unicast_uses_group = sec->unicast_uses_group;
4190 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
4191 }
4192 if (sec->flags & SEC_LEVEL) {
4193 secinfo->level = sec->level;
4194 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
4195 }
4196 if (sec->flags & SEC_ENABLED) {
4197 secinfo->enabled = sec->enabled;
4198 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
4199 }
4200 if (sec->flags & SEC_ENCRYPT) {
4201 secinfo->encrypt = sec->encrypt;
4202 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
4203 }
4204 if (bcm->initialized && !bcm->ieee->host_encrypt) {
4205 if (secinfo->enabled) {
4206 /* upload WEP keys to hardware */
4207 char null_address[6] = { 0 };
4208 u8 algorithm = 0;
4209 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
4210 if (!(sec->flags & (1<<keyidx)))
4211 continue;
4212 switch (sec->encode_alg[keyidx]) {
4213 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
4214 case SEC_ALG_WEP:
4215 algorithm = BCM43xx_SEC_ALGO_WEP;
4216 if (secinfo->key_sizes[keyidx] == 13)
4217 algorithm = BCM43xx_SEC_ALGO_WEP104;
4218 break;
4219 case SEC_ALG_TKIP:
4220 FIXME();
4221 algorithm = BCM43xx_SEC_ALGO_TKIP;
4222 break;
4223 case SEC_ALG_CCMP:
4224 FIXME();
4225 algorithm = BCM43xx_SEC_ALGO_AES;
4226 break;
4227 default:
4228 assert(0);
4229 break;
4230 }
4231 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
4232 bcm->key[keyidx].enabled = 1;
4233 bcm->key[keyidx].algorithm = algorithm;
4234 }
4235 } else
4236 bcm43xx_clear_keys(bcm);
4237 }
4238 spin_unlock_irqrestore(&bcm->lock, flags);
4239}
4240
4241/* hard_start_xmit() callback in struct ieee80211_device */
4242static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
4243 struct net_device *net_dev,
4244 int pri)
4245{
4246 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4247 int err = -ENODEV;
4248 unsigned long flags;
4249
4250 spin_lock_irqsave(&bcm->lock, flags);
4251 if (likely(bcm->initialized))
4252 err = bcm43xx_tx(bcm, txb);
4253 spin_unlock_irqrestore(&bcm->lock, flags);
4254
4255 return err;
4256}
4257
4258static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
4259{
4260 return &(bcm43xx_priv(net_dev)->ieee->stats);
4261}
4262
4263static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
4264{
4265 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4266
4267 bcm43xx_controller_restart(bcm, "TX timeout");
4268}
4269
4270#ifdef CONFIG_NET_POLL_CONTROLLER
4271static void bcm43xx_net_poll_controller(struct net_device *net_dev)
4272{
4273 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4274 unsigned long flags;
4275
4276 local_irq_save(flags);
4277 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
4278 local_irq_restore(flags);
4279}
4280#endif /* CONFIG_NET_POLL_CONTROLLER */
4281
4282static int bcm43xx_net_open(struct net_device *net_dev)
4283{
4284 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4285
4286 return bcm43xx_init_board(bcm);
4287}
4288
4289static int bcm43xx_net_stop(struct net_device *net_dev)
4290{
4291 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4292
4293 ieee80211softmac_stop(net_dev);
4294 bcm43xx_disable_interrupts_sync(bcm, NULL);
4295 bcm43xx_free_board(bcm);
4296
4297 return 0;
4298}
4299
4300static void bcm43xx_init_private(struct bcm43xx_private *bcm,
4301 struct net_device *net_dev,
4302 struct pci_dev *pci_dev,
4303 struct workqueue_struct *wq)
4304{
4305 bcm->ieee = netdev_priv(net_dev);
4306 bcm->softmac = ieee80211_priv(net_dev);
4307 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
4308 bcm->workqueue = wq;
4309
4310#ifdef DEBUG_ENABLE_MMIO_PRINT
4311 bcm43xx_mmioprint_initial(bcm, 1);
4312#else
4313 bcm43xx_mmioprint_initial(bcm, 0);
4314#endif
4315#ifdef DEBUG_ENABLE_PCILOG
4316 bcm43xx_pciprint_initial(bcm, 1);
4317#else
4318 bcm43xx_pciprint_initial(bcm, 0);
4319#endif
4320
4321 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
4322 bcm->pci_dev = pci_dev;
4323 bcm->net_dev = net_dev;
4324 if (modparam_bad_frames_preempt)
4325 bcm->bad_frames_preempt = 1;
4326 spin_lock_init(&bcm->lock);
4327 tasklet_init(&bcm->isr_tasklet,
4328 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
4329 (unsigned long)bcm);
4330 tasklet_disable_nosync(&bcm->isr_tasklet);
4331 if (modparam_pio) {
4332 bcm->pio_mode = 1;
4333 } else {
4334 if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK) == 0) {
4335 bcm->pio_mode = 0;
4336 } else {
4337 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
4338 bcm->pio_mode = 1;
4339 }
4340 }
4341 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
4342
4343 /* default to sw encryption for now */
4344 bcm->ieee->host_build_iv = 0;
4345 bcm->ieee->host_encrypt = 1;
4346 bcm->ieee->host_decrypt = 1;
4347
4348 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
4349 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
4350 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
4351 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
4352}
4353
4354static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
4355 const struct pci_device_id *ent)
4356{
4357 struct net_device *net_dev;
4358 struct bcm43xx_private *bcm;
4359 struct workqueue_struct *wq;
4360 int err;
4361
4362#ifdef CONFIG_BCM947XX
4363 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
4364 return -ENODEV;
4365#endif
4366
4367#ifdef DEBUG_SINGLE_DEVICE_ONLY
4368 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
4369 return -ENODEV;
4370#endif
4371
4372 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
4373 if (!net_dev) {
4374 printk(KERN_ERR PFX
4375 "could not allocate ieee80211 device %s\n",
4376 pci_name(pdev));
4377 err = -ENOMEM;
4378 goto out;
4379 }
4380 /* initialize the net_device struct */
4381 SET_MODULE_OWNER(net_dev);
4382 SET_NETDEV_DEV(net_dev, &pdev->dev);
4383
4384 net_dev->open = bcm43xx_net_open;
4385 net_dev->stop = bcm43xx_net_stop;
4386 net_dev->get_stats = bcm43xx_net_get_stats;
4387 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
4388#ifdef CONFIG_NET_POLL_CONTROLLER
4389 net_dev->poll_controller = bcm43xx_net_poll_controller;
4390#endif
4391 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
4392 net_dev->irq = pdev->irq;
4393 net_dev->watchdog_timeo = BCM43xx_TX_TIMEOUT;
4394
4395 /* initialize the bcm43xx_private struct */
4396 bcm = bcm43xx_priv(net_dev);
4397 memset(bcm, 0, sizeof(*bcm));
4398 wq = create_workqueue(DRV_NAME "_wq");
4399 if (!wq) {
4400 err = -ENOMEM;
4401 goto err_free_netdev;
4402 }
4403 bcm43xx_init_private(bcm, net_dev, pdev, wq);
4404
4405 pci_set_drvdata(pdev, net_dev);
4406
4407 err = bcm43xx_attach_board(bcm);
4408 if (err)
4409 goto err_destroy_wq;
4410
4411 err = register_netdev(net_dev);
4412 if (err) {
4413 printk(KERN_ERR PFX "Cannot register net device, "
4414 "aborting.\n");
4415 err = -ENOMEM;
4416 goto err_detach_board;
4417 }
4418
4419 bcm43xx_debugfs_add_device(bcm);
4420
4421 assert(err == 0);
4422out:
4423 return err;
4424
4425err_detach_board:
4426 bcm43xx_detach_board(bcm);
4427err_destroy_wq:
4428 destroy_workqueue(wq);
4429err_free_netdev:
4430 free_ieee80211softmac(net_dev);
4431 goto out;
4432}
4433
4434static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
4435{
4436 struct net_device *net_dev = pci_get_drvdata(pdev);
4437 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4438
4439 bcm43xx_debugfs_remove_device(bcm);
4440 unregister_netdev(net_dev);
4441 bcm43xx_detach_board(bcm);
4442 assert(bcm->ucode == NULL);
4443 destroy_workqueue(bcm->workqueue);
4444 free_ieee80211softmac(net_dev);
4445}
4446
4447/* Hard-reset the chip. Do not call this directly.
4448 * Use bcm43xx_controller_restart()
4449 */
4450static void bcm43xx_chip_reset(void *_bcm)
4451{
4452 struct bcm43xx_private *bcm = _bcm;
4453 struct net_device *net_dev = bcm->net_dev;
4454 struct pci_dev *pci_dev = bcm->pci_dev;
4455 struct workqueue_struct *wq = bcm->workqueue;
4456 int err;
4457 int was_initialized = bcm->initialized;
4458
4459 netif_stop_queue(bcm->net_dev);
4460 tasklet_disable(&bcm->isr_tasklet);
4461
4462 bcm->firmware_norelease = 1;
4463 if (was_initialized)
4464 bcm43xx_free_board(bcm);
4465 bcm->firmware_norelease = 0;
4466 bcm43xx_detach_board(bcm);
4467 bcm43xx_init_private(bcm, net_dev, pci_dev, wq);
4468 err = bcm43xx_attach_board(bcm);
4469 if (err)
4470 goto failure;
4471 if (was_initialized) {
4472 err = bcm43xx_init_board(bcm);
4473 if (err)
4474 goto failure;
4475 }
4476 netif_wake_queue(bcm->net_dev);
4477 printk(KERN_INFO PFX "Controller restarted\n");
4478
4479 return;
4480failure:
4481 printk(KERN_ERR PFX "Controller restart failed\n");
4482}
4483
4484/* Hard-reset the chip.
4485 * This can be called from interrupt or process context.
4486 * Make sure to _not_ re-enable device interrupts after this has been called.
4487*/
4488void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
4489{
4490 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
4491 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
4492 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
4493 queue_work(bcm->workqueue, &bcm->restart_work);
4494}
4495
4496#ifdef CONFIG_PM
4497
4498static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
4499{
4500 struct net_device *net_dev = pci_get_drvdata(pdev);
4501 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4502 unsigned long flags;
4503 int try_to_shutdown = 0, err;
4504
4505 dprintk(KERN_INFO PFX "Suspending...\n");
4506
4507 spin_lock_irqsave(&bcm->lock, flags);
4508 bcm->was_initialized = bcm->initialized;
4509 if (bcm->initialized)
4510 try_to_shutdown = 1;
4511 spin_unlock_irqrestore(&bcm->lock, flags);
4512
4513 netif_device_detach(net_dev);
4514 if (try_to_shutdown) {
4515 ieee80211softmac_stop(net_dev);
4516 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
4517 if (unlikely(err)) {
4518 dprintk(KERN_ERR PFX "Suspend failed.\n");
4519 return -EAGAIN;
4520 }
4521 bcm->firmware_norelease = 1;
4522 bcm43xx_free_board(bcm);
4523 bcm->firmware_norelease = 0;
4524 }
4525 bcm43xx_chipset_detach(bcm);
4526
4527 pci_save_state(pdev);
4528 pci_disable_device(pdev);
4529 pci_set_power_state(pdev, pci_choose_state(pdev, state));
4530
4531 dprintk(KERN_INFO PFX "Device suspended.\n");
4532
4533 return 0;
4534}
4535
4536static int bcm43xx_resume(struct pci_dev *pdev)
4537{
4538 struct net_device *net_dev = pci_get_drvdata(pdev);
4539 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4540 int err = 0;
4541
4542 dprintk(KERN_INFO PFX "Resuming...\n");
4543
4544 pci_set_power_state(pdev, 0);
4545 pci_enable_device(pdev);
4546 pci_restore_state(pdev);
4547
4548 bcm43xx_chipset_attach(bcm);
4549 if (bcm->was_initialized) {
4550 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
4551 err = bcm43xx_init_board(bcm);
4552 }
4553 if (err) {
4554 printk(KERN_ERR PFX "Resume failed!\n");
4555 return err;
4556 }
4557
4558 netif_device_attach(net_dev);
4559
4560 /*FIXME: This should be handled by softmac instead. */
4561 schedule_work(&bcm->softmac->associnfo.work);
4562
4563 dprintk(KERN_INFO PFX "Device resumed.\n");
4564
4565 return 0;
4566}
4567
4568#endif /* CONFIG_PM */
4569
4570static struct pci_driver bcm43xx_pci_driver = {
4571 .name = BCM43xx_DRIVER_NAME,
4572 .id_table = bcm43xx_pci_tbl,
4573 .probe = bcm43xx_init_one,
4574 .remove = __devexit_p(bcm43xx_remove_one),
4575#ifdef CONFIG_PM
4576 .suspend = bcm43xx_suspend,
4577 .resume = bcm43xx_resume,
4578#endif /* CONFIG_PM */
4579};
4580
4581static int __init bcm43xx_init(void)
4582{
4583 printk(KERN_INFO BCM43xx_DRIVER_NAME "\n");
4584 bcm43xx_debugfs_init();
4585 return pci_register_driver(&bcm43xx_pci_driver);
4586}
4587
4588static void __exit bcm43xx_exit(void)
4589{
4590 pci_unregister_driver(&bcm43xx_pci_driver);
4591 bcm43xx_debugfs_exit();
4592}
4593
4594module_init(bcm43xx_init)
4595module_exit(bcm43xx_exit)
4596
4597/* vim: set ts=8 sw=8 sts=8: */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
new file mode 100644
index 000000000000..1d3eddd314bc
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -0,0 +1,283 @@
1/*
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#ifndef BCM43xx_MAIN_H_
32#define BCM43xx_MAIN_H_
33
34#include "bcm43xx.h"
35
36#ifdef CONFIG_BCM947XX
37#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
38
39static inline void e_aton(char *str, char *dest)
40{
41 int i = 0;
42 u16 *d = (u16 *) dest;
43
44 for (;;) {
45 dest[i++] = (char) simple_strtoul(str, NULL, 16);
46 str += 2;
47 if (!*str++ || i == 6)
48 break;
49 }
50 for (i = 0; i < 3; i++)
51 d[i] = cpu_to_be16(d[i]);
52}
53#endif
54
55
56#define _bcm43xx_declare_plcp_hdr(size) \
57 struct bcm43xx_plcp_hdr##size { \
58 union { \
59 __le32 data; \
60 __u8 raw[size]; \
61 } __attribute__((__packed__)); \
62 } __attribute__((__packed__))
63
64/* struct bcm43xx_plcp_hdr4 */
65_bcm43xx_declare_plcp_hdr(4);
66/* struct bcm430c_plcp_hdr6 */
67_bcm43xx_declare_plcp_hdr(6);
68
69#undef _bcm43xx_declare_plcp_hdr
70
71
72#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
73#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
74/* Magic helper macro to pad structures. Ignore those above. It's magic. */
75#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
76
77
78/* Device specific TX header. To be prepended to TX frames. */
79struct bcm43xx_txhdr {
80 union {
81 struct {
82 u16 flags;
83 u16 wsec_rate;
84 u16 frame_control;
85 u16 unknown_zeroed_0;
86 u16 control;
87 unsigned char wep_iv[10];
88 unsigned char unknown_wsec_tkip_data[3]; //FIXME
89 PAD_BYTES(3);
90 unsigned char mac1[6];
91 u16 unknown_zeroed_1;
92 struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp;
93 u16 rts_cts_dur_fallback;
94 struct bcm43xx_plcp_hdr4 fallback_plcp;
95 u16 fallback_dur_id;
96 PAD_BYTES(2);
97 u16 cookie;
98 u16 unknown_scb_stuff; //FIXME
99 struct bcm43xx_plcp_hdr6 rts_cts_plcp;
100 u16 rts_cts_frame_type;
101 u16 rts_cts_dur;
102 unsigned char rts_cts_mac1[6];
103 unsigned char rts_cts_mac2[6];
104 PAD_BYTES(2);
105 struct bcm43xx_plcp_hdr6 plcp;
106 } __attribute__((__packed__));
107
108 unsigned char raw[82];
109 } __attribute__((__packed__));
110} __attribute__((__packed__));
111
112struct sk_buff;
113
114void FASTCALL(bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
115 struct bcm43xx_txhdr *txhdr,
116 const unsigned char *fragment_data,
117 const unsigned int fragment_len,
118 const int is_first_fragment,
119 const u16 cookie));
120
121/* RX header as received from the hardware. */
122struct bcm43xx_rxhdr {
123 /* Frame Length. Must be generated explicitely in PIO mode. */
124 __le16 frame_length;
125 PAD_BYTES(2);
126 /* Flags field 1 */
127 __le16 flags1;
128 u8 rssi;
129 u8 signal_quality;
130 PAD_BYTES(2);
131 /* Flags field 3 */
132 __le16 flags3;
133 /* Flags field 2 */
134 __le16 flags2;
135 /* Lower 16bits of the TSF at the time the frame started. */
136 __le16 mactime;
137 PAD_BYTES(14);
138} __attribute__((__packed__));
139
140#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0)
141/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */
142#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7)
143#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14)
144
145#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0)
146#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2)
147/*FIXME: WEP related flags */
148
149#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10)
150
151/* Transmit Status as received from the hardware. */
152struct bcm43xx_hwxmitstatus {
153 PAD_BYTES(4);
154 __le16 cookie;
155 u8 flags;
156 u8 cnt1:4,
157 cnt2:4;
158 PAD_BYTES(2);
159 __le16 seq;
160 __le16 unknown; //FIXME
161} __attribute__((__packed__));
162
163/* Transmit Status in CPU byteorder. */
164struct bcm43xx_xmitstatus {
165 u16 cookie;
166 u8 flags;
167 u8 cnt1:4,
168 cnt2:4;
169 u16 seq;
170 u16 unknown; //FIXME
171};
172
173#define BCM43xx_TXSTAT_FLAG_ACK 0x01
174//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02
175//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04
176//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08
177//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10
178#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20
179//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40
180//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80
181
182struct bcm43xx_xmitstatus_queue {
183 struct list_head list;
184 struct bcm43xx_hwxmitstatus status;
185};
186
187
188/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
189static inline
190u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm,
191 int freq)
192{
193 u8 channel;
194
195 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) {
196 channel = (freq - 5000) / 5;
197 } else {
198 if (freq == 2484)
199 channel = 14;
200 else
201 channel = (freq - 2407) / 5;
202 }
203
204 return channel;
205}
206
207/* Lightweight function to convert a channel number to a frequency (in Mhz). */
208static inline
209int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
210 u8 channel)
211{
212 int freq;
213
214 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) {
215 freq = 5000 + (5 * channel);
216 } else {
217 if (channel == 14)
218 freq = 2484;
219 else
220 freq = 2407 + (5 * channel);
221 }
222
223 return freq;
224}
225
226/* Lightweight function to check if a channel number is valid.
227 * Note that this does _NOT_ check for geographical restrictions!
228 */
229static inline
230int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
231 u8 channel)
232{
233 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) {
234 if (channel <= 200)
235 return 1;
236 } else {
237 if (channel >= 1 && channel <= 14)
238 return 1;
239 }
240
241 return 0;
242}
243
244void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
245void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
246
247int FASTCALL(bcm43xx_rx(struct bcm43xx_private *bcm,
248 struct sk_buff *skb,
249 struct bcm43xx_rxhdr *rxhdr));
250
251void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
252 int iw_mode);
253
254u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
255 u16 routing, u16 offset);
256u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
257 u16 routing, u16 offset);
258void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
259 u16 routing, u16 offset,
260 u32 value);
261void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
262 u16 routing, u16 offset,
263 u16 value);
264
265void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
266
267int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
268
269void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
270
271int bcm43xx_pci_read_config_16(struct pci_dev *pdev, u16 offset, u16 *val);
272int bcm43xx_pci_read_config_32(struct pci_dev *pdev, u16 offset, u32 *val);
273int bcm43xx_pci_write_config_16(struct pci_dev *pdev, int offset, u16 val);
274int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val);
275
276void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
277void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
278
279u8 bcm43xx_sprom_crc(const u16 *sprom);
280
281void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
282
283#endif /* BCM43xx_MAIN_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
new file mode 100644
index 000000000000..41b9cd7fc9e2
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -0,0 +1,2122 @@
1/*
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/pci.h>
33#include <linux/types.h>
34
35#include "bcm43xx.h"
36#include "bcm43xx_phy.h"
37#include "bcm43xx_main.h"
38#include "bcm43xx_radio.h"
39#include "bcm43xx_ilt.h"
40#include "bcm43xx_power.h"
41
42
43static const s8 bcm43xx_tssi2dbm_b_table[] = {
44 0x4D, 0x4C, 0x4B, 0x4A,
45 0x4A, 0x49, 0x48, 0x47,
46 0x47, 0x46, 0x45, 0x45,
47 0x44, 0x43, 0x42, 0x42,
48 0x41, 0x40, 0x3F, 0x3E,
49 0x3D, 0x3C, 0x3B, 0x3A,
50 0x39, 0x38, 0x37, 0x36,
51 0x35, 0x34, 0x32, 0x31,
52 0x30, 0x2F, 0x2D, 0x2C,
53 0x2B, 0x29, 0x28, 0x26,
54 0x25, 0x23, 0x21, 0x1F,
55 0x1D, 0x1A, 0x17, 0x14,
56 0x10, 0x0C, 0x06, 0x00,
57 -7, -7, -7, -7,
58 -7, -7, -7, -7,
59 -7, -7, -7, -7,
60};
61
62static const s8 bcm43xx_tssi2dbm_g_table[] = {
63 77, 77, 77, 76,
64 76, 76, 75, 75,
65 74, 74, 73, 73,
66 73, 72, 72, 71,
67 71, 70, 70, 69,
68 68, 68, 67, 67,
69 66, 65, 65, 64,
70 63, 63, 62, 61,
71 60, 59, 58, 57,
72 56, 55, 54, 53,
73 52, 50, 49, 47,
74 45, 43, 40, 37,
75 33, 28, 22, 14,
76 5, -7, -20, -20,
77 -20, -20, -20, -20,
78 -20, -20, -20, -20,
79};
80
81static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
82
83
84void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
85{
86 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
87
88 assert(irqs_disabled());
89 if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) {
90 phy->is_locked = 0;
91 return;
92 }
93 if (bcm->current_core->rev < 3) {
94 bcm43xx_mac_suspend(bcm);
95 spin_lock(&phy->lock);
96 } else {
97 if (bcm->ieee->iw_mode != IW_MODE_MASTER)
98 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
99 }
100 phy->is_locked = 1;
101}
102
103void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm)
104{
105 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
106
107 assert(irqs_disabled());
108 if (bcm->current_core->rev < 3) {
109 if (phy->is_locked) {
110 spin_unlock(&phy->lock);
111 bcm43xx_mac_enable(bcm);
112 }
113 } else {
114 if (bcm->ieee->iw_mode != IW_MODE_MASTER)
115 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
116 }
117 phy->is_locked = 0;
118}
119
120u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset)
121{
122 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset);
123 return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA);
124}
125
126void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
127{
128 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset);
129 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val);
130}
131
132void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
133{
134 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
135 unsigned long flags;
136
137 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
138 if (phy->calibrated)
139 return;
140 if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
141 /* We do not want to be preempted while calibrating
142 * the hardware.
143 */
144 local_irq_save(flags);
145
146 bcm43xx_wireless_core_reset(bcm, 0);
147 bcm43xx_phy_initg(bcm);
148 bcm43xx_wireless_core_reset(bcm, 1);
149
150 local_irq_restore(flags);
151 }
152 phy->calibrated = 1;
153}
154
155/* Connect the PHY
156 * http://bcm-specs.sipsolutions.net/SetPHY
157 */
158int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
159{
160 u32 flags;
161
162 if (bcm->current_core->rev < 5) {
163 if (connect) {
164 bcm->current_core->phy->connected = 1;
165 dprintk(KERN_INFO PFX "PHY connected\n");
166 } else {
167 bcm->current_core->phy->connected = 0;
168 dprintk(KERN_INFO PFX "PHY disconnected\n");
169 }
170 return 0;
171 }
172
173 flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
174 if (connect) {
175 if (!(flags & 0x00010000))
176 return -ENODEV;
177 bcm->current_core->phy->connected = 1;
178
179 flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
180 flags |= (0x800 << 18);
181 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
182 dprintk(KERN_INFO PFX "PHY connected\n");
183 } else {
184 if (!(flags & 0x00020000))
185 return -ENODEV;
186 bcm->current_core->phy->connected = 0;
187
188 flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
189 flags &= ~(0x800 << 18);
190 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
191 dprintk(KERN_INFO PFX "PHY disconnected\n");
192 }
193
194 return 0;
195}
196
197/* intialize B PHY power control
198 * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
199 */
200static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm)
201{
202 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
203 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
204 u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0;
205 int must_reset_txpower = 0;
206
207 assert(phy->type != BCM43xx_PHYTYPE_A);
208 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
209 (bcm->board_type == 0x0416))
210 return;
211
212 bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF);
213 bcm43xx_phy_write(bcm, 0x0028, 0x8018);
214
215 if (phy->type == BCM43xx_PHYTYPE_G) {
216 if (!phy->connected)
217 return;
218 bcm43xx_phy_write(bcm, 0x047A, 0xC111);
219 }
220 if (phy->savedpctlreg != 0xFFFF)
221 return;
222
223 if (phy->type == BCM43xx_PHYTYPE_B &&
224 phy->rev >= 2 &&
225 radio->version == 0x2050) {
226 bcm43xx_radio_write16(bcm, 0x0076,
227 bcm43xx_radio_read16(bcm, 0x0076) | 0x0084);
228 } else {
229 saved_batt = radio->txpower[0];
230 saved_ratt = radio->txpower[1];
231 saved_txctl1 = radio->txpower[2];
232 if ((radio->revision >= 6) && (radio->revision <= 8)
233 && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
234 bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0);
235 else
236 bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0);
237 must_reset_txpower = 1;
238 }
239 bcm43xx_dummy_transmission(bcm);
240
241 phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL);
242
243 if (must_reset_txpower)
244 bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1);
245 else
246 bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B);
247 bcm43xx_radio_clear_tssi(bcm);
248}
249
250static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
251{
252 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
253 u16 offset = 0x0000;
254
255 if (phy->rev == 1)
256 offset = 0x4C00;
257
258 bcm43xx_ilt_write16(bcm, offset, 0x00FE);
259 bcm43xx_ilt_write16(bcm, offset + 1, 0x000D);
260 bcm43xx_ilt_write16(bcm, offset + 2, 0x0013);
261 bcm43xx_ilt_write16(bcm, offset + 3, 0x0019);
262
263 if (phy->rev == 1) {
264 bcm43xx_ilt_write16(bcm, 0x1800, 0x2710);
265 bcm43xx_ilt_write16(bcm, 0x1801, 0x9B83);
266 bcm43xx_ilt_write16(bcm, 0x1802, 0x9B83);
267 bcm43xx_ilt_write16(bcm, 0x1803, 0x0F8D);
268 bcm43xx_phy_write(bcm, 0x0455, 0x0004);
269 }
270
271 bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700);
272 bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F);
273 bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80);
274 bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300);
275
276 bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008);
277
278 bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008);
279 bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600);
280 bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700);
281 bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100);
282
283 if (phy->rev == 1)
284 bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007);
285
286 bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C);
287 bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200);
288 bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C);
289 bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020);
290 bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200);
291 bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E);
292 bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00);
293 bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028);
294 bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00);
295
296 if (phy->rev == 1) {
297 bcm43xx_phy_write(bcm, 0x0430, 0x092B);
298 bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002);
299 } else {
300 bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1);
301 bcm43xx_phy_write(bcm, 0x041F, 0x287A);
302 bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004);
303 }
304
305 if (phy->rev > 2) {
306 bcm43xx_phy_write(bcm, 0x0422, 0x287A);
307 bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000);
308 }
309
310 bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
311 bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
312
313 if (phy->rev == 1) {
314 bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
315 bcm43xx_phy_write(bcm, 0x048B, 0x005E);
316 bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
317 bcm43xx_phy_write(bcm, 0x048D, 0x0002);
318 }
319
320 bcm43xx_ilt_write16(bcm, offset + 0x0800, 0);
321 bcm43xx_ilt_write16(bcm, offset + 0x0801, 7);
322 bcm43xx_ilt_write16(bcm, offset + 0x0802, 16);
323 bcm43xx_ilt_write16(bcm, offset + 0x0803, 28);
324}
325
326static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
327{
328 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
329 u16 i;
330
331 assert(phy->type == BCM43xx_PHYTYPE_G);
332 if (phy->rev == 1) {
333 bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
334 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
335 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
336 bcm43xx_phy_write(bcm, 0x042C, 0x005A);
337 bcm43xx_phy_write(bcm, 0x0427, 0x001A);
338
339 for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++)
340 bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]);
341 for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++)
342 bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]);
343 for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
344 bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
345 } else {
346 /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
347 bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654);
348
349 if (phy->rev == 2) {
350 bcm43xx_phy_write(bcm, 0x04C0, 0x1861);
351 bcm43xx_phy_write(bcm, 0x04C1, 0x0271);
352 } else if (phy->rev > 2) {
353 bcm43xx_phy_write(bcm, 0x04C0, 0x0098);
354 bcm43xx_phy_write(bcm, 0x04C1, 0x0070);
355 bcm43xx_phy_write(bcm, 0x04C9, 0x0080);
356 }
357 bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800);
358
359 for (i = 0; i < 64; i++)
360 bcm43xx_ilt_write16(bcm, 0x4000 + i, i);
361 for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++)
362 bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]);
363 }
364
365 if (phy->rev <= 2)
366 for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
367 bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
368 else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
369 for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
370 bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
371 else
372 for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
373 bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]);
374
375 if (phy->rev == 2)
376 for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
377 bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
378 else if ((phy->rev > 2) && (phy->rev <= 7))
379 for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
380 bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
381
382 if (phy->rev == 1) {
383 for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
384 bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
385 for (i = 0; i < 4; i++) {
386 bcm43xx_ilt_write16(bcm, 0x5404 + i, 0x0020);
387 bcm43xx_ilt_write16(bcm, 0x5408 + i, 0x0020);
388 bcm43xx_ilt_write16(bcm, 0x540C + i, 0x0020);
389 bcm43xx_ilt_write16(bcm, 0x5410 + i, 0x0020);
390 }
391 bcm43xx_phy_agcsetup(bcm);
392
393 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
394 (bcm->board_type == 0x0416) &&
395 (bcm->board_revision == 0x0017))
396 return;
397
398 bcm43xx_ilt_write16(bcm, 0x5001, 0x0002);
399 bcm43xx_ilt_write16(bcm, 0x5002, 0x0001);
400 } else {
401 for (i = 0; i <= 0x2F; i++)
402 bcm43xx_ilt_write16(bcm, 0x1000 + i, 0x0820);
403 bcm43xx_phy_agcsetup(bcm);
404 bcm43xx_phy_read(bcm, 0x0400); /* dummy read */
405 bcm43xx_phy_write(bcm, 0x0403, 0x1000);
406 bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F);
407 bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014);
408
409 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
410 (bcm->board_type == 0x0416) &&
411 (bcm->board_revision == 0x0017))
412 return;
413
414 bcm43xx_ilt_write16(bcm, 0x0401, 0x0002);
415 bcm43xx_ilt_write16(bcm, 0x0402, 0x0001);
416 }
417}
418
419/* Initialize the noisescaletable for APHY */
420static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm)
421{
422 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
423 int i;
424
425 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400);
426 for (i = 0; i < 12; i++) {
427 if (phy->rev == 2)
428 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
429 else
430 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
431 }
432 if (phy->rev == 2)
433 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700);
434 else
435 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300);
436 for (i = 0; i < 11; i++) {
437 if (phy->rev == 2)
438 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
439 else
440 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
441 }
442 if (phy->rev == 2)
443 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067);
444 else
445 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023);
446}
447
448static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm)
449{
450 u16 i;
451
452 assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_A);
453 switch (bcm->current_core->phy->rev) {
454 case 2:
455 bcm43xx_phy_write(bcm, 0x008E, 0x3800);
456 bcm43xx_phy_write(bcm, 0x0035, 0x03FF);
457 bcm43xx_phy_write(bcm, 0x0036, 0x0400);
458
459 bcm43xx_ilt_write16(bcm, 0x3807, 0x0051);
460
461 bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
462 bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
463 bcm43xx_ilt_write16(bcm, 0x3C0C, 0x07BF);
464 bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
465
466 bcm43xx_phy_write(bcm, 0x0024, 0x4680);
467 bcm43xx_phy_write(bcm, 0x0020, 0x0003);
468 bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
469 bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
470
471 bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
472 bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF);
473 bcm43xx_phy_write(bcm, 0x008E, 0x58C1);
474
475 bcm43xx_ilt_write16(bcm, 0x0803, 0x000F);
476 bcm43xx_ilt_write16(bcm, 0x0804, 0x001F);
477 bcm43xx_ilt_write16(bcm, 0x0805, 0x002A);
478 bcm43xx_ilt_write16(bcm, 0x0805, 0x0030);
479 bcm43xx_ilt_write16(bcm, 0x0807, 0x003A);
480
481 bcm43xx_ilt_write16(bcm, 0x0000, 0x0013);
482 bcm43xx_ilt_write16(bcm, 0x0001, 0x0013);
483 bcm43xx_ilt_write16(bcm, 0x0002, 0x0013);
484 bcm43xx_ilt_write16(bcm, 0x0003, 0x0013);
485 bcm43xx_ilt_write16(bcm, 0x0004, 0x0015);
486 bcm43xx_ilt_write16(bcm, 0x0005, 0x0015);
487 bcm43xx_ilt_write16(bcm, 0x0006, 0x0019);
488
489 bcm43xx_ilt_write16(bcm, 0x0404, 0x0003);
490 bcm43xx_ilt_write16(bcm, 0x0405, 0x0003);
491 bcm43xx_ilt_write16(bcm, 0x0406, 0x0007);
492
493 for (i = 0; i < 16; i++)
494 bcm43xx_ilt_write16(bcm, 0x4000 + i, (0x8 + i) & 0x000F);
495
496 bcm43xx_ilt_write16(bcm, 0x3003, 0x1044);
497 bcm43xx_ilt_write16(bcm, 0x3004, 0x7201);
498 bcm43xx_ilt_write16(bcm, 0x3006, 0x0040);
499 bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008);
500
501 for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++)
502 bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]);
503 for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++)
504 bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]);
505 for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
506 bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
507 bcm43xx_phy_init_noisescaletbl(bcm);
508 for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
509 bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
510 break;
511 case 3:
512 for (i = 0; i < 64; i++)
513 bcm43xx_ilt_write16(bcm, 0x4000 + i, i);
514
515 bcm43xx_ilt_write16(bcm, 0x3807, 0x0051);
516
517 bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
518 bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
519 bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
520
521 bcm43xx_phy_write(bcm, 0x0024, 0x4680);
522 bcm43xx_phy_write(bcm, 0x0020, 0x0003);
523 bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
524 bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
525 bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
526
527 bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008);
528 for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++)
529 bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]);
530 bcm43xx_phy_init_noisescaletbl(bcm);
531 for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
532 bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
533
534 bcm43xx_phy_write(bcm, 0x0003, 0x1808);
535
536 bcm43xx_ilt_write16(bcm, 0x0803, 0x000F);
537 bcm43xx_ilt_write16(bcm, 0x0804, 0x001F);
538 bcm43xx_ilt_write16(bcm, 0x0805, 0x002A);
539 bcm43xx_ilt_write16(bcm, 0x0805, 0x0030);
540 bcm43xx_ilt_write16(bcm, 0x0807, 0x003A);
541
542 bcm43xx_ilt_write16(bcm, 0x0000, 0x0013);
543 bcm43xx_ilt_write16(bcm, 0x0001, 0x0013);
544 bcm43xx_ilt_write16(bcm, 0x0002, 0x0013);
545 bcm43xx_ilt_write16(bcm, 0x0003, 0x0013);
546 bcm43xx_ilt_write16(bcm, 0x0004, 0x0015);
547 bcm43xx_ilt_write16(bcm, 0x0005, 0x0015);
548 bcm43xx_ilt_write16(bcm, 0x0006, 0x0019);
549
550 bcm43xx_ilt_write16(bcm, 0x0404, 0x0003);
551 bcm43xx_ilt_write16(bcm, 0x0405, 0x0003);
552 bcm43xx_ilt_write16(bcm, 0x0406, 0x0007);
553
554 bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F);
555 bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014);
556 break;
557 default:
558 assert(0);
559 }
560}
561
562/* Initialize APHY. This is also called for the GPHY in some cases. */
563static void bcm43xx_phy_inita(struct bcm43xx_private *bcm)
564{
565 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
566 u16 tval;
567
568 if (phy->type == BCM43xx_PHYTYPE_A) {
569 bcm43xx_phy_setupa(bcm);
570 } else {
571 bcm43xx_phy_setupg(bcm);
572 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
573 bcm43xx_phy_write(bcm, 0x046E, 0x03CF);
574 return;
575 }
576
577 bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
578 (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340);
579 bcm43xx_phy_write(bcm, 0x0034, 0x0001);
580
581 TODO();//TODO: RSSI AGC
582 bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
583 bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14));
584 bcm43xx_radio_init2060(bcm);
585
586 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)
587 && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) {
588 if (bcm->current_core->radio->lofcal == 0xFFFF) {
589 TODO();//TODO: LOF Cal
590 bcm43xx_radio_set_tx_iq(bcm);
591 } else
592 bcm43xx_radio_write16(bcm, 0x001E, bcm->current_core->radio->lofcal);
593 }
594
595 bcm43xx_phy_write(bcm, 0x007A, 0xF111);
596
597 if (phy->savedpctlreg == 0xFFFF) {
598 bcm43xx_radio_write16(bcm, 0x0019, 0x0000);
599 bcm43xx_radio_write16(bcm, 0x0017, 0x0020);
600
601 tval = bcm43xx_ilt_read16(bcm, 0x3001);
602 if (phy->rev == 1) {
603 bcm43xx_ilt_write16(bcm, 0x3001,
604 (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFF87)
605 | 0x0058);
606 } else {
607 bcm43xx_ilt_write16(bcm, 0x3001,
608 (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFFC3)
609 | 0x002C);
610 }
611 bcm43xx_dummy_transmission(bcm);
612 phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL);
613 bcm43xx_ilt_write16(bcm, 0x3001, tval);
614
615 bcm43xx_radio_set_txpower_a(bcm, 0x0018);
616 }
617 bcm43xx_radio_clear_tssi(bcm);
618}
619
620static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm)
621{
622 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
623 u16 offset, val;
624
625 bcm43xx_write16(bcm, 0x03EC, 0x3F22);
626 bcm43xx_phy_write(bcm, 0x0020, 0x301C);
627 bcm43xx_phy_write(bcm, 0x0026, 0x0000);
628 bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
629 bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
630 val = 0x3C3D;
631 for (offset = 0x0089; offset < 0x00A7; offset++) {
632 bcm43xx_phy_write(bcm, offset, val);
633 val -= 0x0202;
634 }
635 bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
636 if (radio->channel == 0xFF)
637 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
638 else
639 bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
640 if (radio->version != 0x2050) {
641 bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
642 bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
643 }
644 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
645 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
646 if (radio->version == 0x2050) {
647 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
648 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
649 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
650 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
651 bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
652 bcm43xx_phy_write(bcm, 0x0038, 0x0677);
653 bcm43xx_radio_init2050(bcm);
654 }
655 bcm43xx_phy_write(bcm, 0x0014, 0x0080);
656 bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
657 bcm43xx_phy_write(bcm, 0x0032, 0x00CC);
658 bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
659 bcm43xx_phy_lo_b_measure(bcm);
660 bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
661 if (radio->version != 0x2050)
662 bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
663 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000);
664 bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
665 if (radio->version != 0x2050)
666 bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
667 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
668 bcm43xx_phy_init_pctl(bcm);
669}
670
671static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm)
672{
673 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
674 u16 offset, val;
675
676 bcm43xx_write16(bcm, 0x03EC, 0x3F22);
677 bcm43xx_phy_write(bcm, 0x0020, 0x301C);
678 bcm43xx_phy_write(bcm, 0x0026, 0x0000);
679 bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
680 bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
681 val = 0x3C3D;
682 for (offset = 0x0089; offset < 0x00A7; offset++) {
683 bcm43xx_phy_write(bcm, offset, val);
684 val -= 0x0202;
685 }
686 bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
687 if (radio->channel == 0xFF)
688 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
689 else
690 bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
691 if (radio->version != 0x2050) {
692 bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
693 bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
694 }
695 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
696 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
697 if (radio->version == 0x2050) {
698 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
699 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
700 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
701 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
702 bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
703 bcm43xx_phy_write(bcm, 0x0038, 0x0677);
704 bcm43xx_radio_init2050(bcm);
705 }
706 bcm43xx_phy_write(bcm, 0x0014, 0x0080);
707 bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
708 if (radio->version == 0x2050)
709 bcm43xx_phy_write(bcm, 0x0032, 0x00E0);
710 bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
711
712 bcm43xx_phy_lo_b_measure(bcm);
713
714 bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
715 if (radio->version == 0x2050)
716 bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
717 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100);
718 bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
719 if (radio->version == 0x2050)
720 bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
721 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
722 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
723 bcm43xx_calc_nrssi_slope(bcm);
724 bcm43xx_calc_nrssi_threshold(bcm);
725 }
726 bcm43xx_phy_init_pctl(bcm);
727}
728
729static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
730{
731 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
732 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
733 u16 offset;
734
735 if (phy->version == 1 &&
736 radio->version == 0x2050) {
737 bcm43xx_radio_write16(bcm, 0x007A,
738 bcm43xx_radio_read16(bcm, 0x007A)
739 | 0x0050);
740 }
741 if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) &&
742 (bcm->board_type != 0x0416)) {
743 for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
744 bcm43xx_phy_write(bcm, offset,
745 (bcm43xx_phy_read(bcm, offset) + 0x2020)
746 & 0x3F3F);
747 }
748 }
749 bcm43xx_phy_write(bcm, 0x0035,
750 (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF)
751 | 0x0700);
752 if (radio->version == 0x2050)
753 bcm43xx_phy_write(bcm, 0x0038, 0x0667);
754
755 if (phy->connected) {
756 if (radio->version == 0x2050) {
757 bcm43xx_radio_write16(bcm, 0x007A,
758 bcm43xx_radio_read16(bcm, 0x007A)
759 | 0x0020);
760 bcm43xx_radio_write16(bcm, 0x0051,
761 bcm43xx_radio_read16(bcm, 0x0051)
762 | 0x0004);
763 }
764 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000);
765
766 bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
767 bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
768
769 bcm43xx_phy_write(bcm, 0x001C, 0x186A);
770
771 bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900);
772 bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064);
773 bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A);
774 }
775
776 if (bcm->bad_frames_preempt) {
777 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
778 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11));
779 }
780
781 if (phy->version == 1 && radio->version == 0x2050) {
782 bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
783 bcm43xx_phy_write(bcm, 0x0021, 0x3763);
784 bcm43xx_phy_write(bcm, 0x0022, 0x1BC3);
785 bcm43xx_phy_write(bcm, 0x0023, 0x06F9);
786 bcm43xx_phy_write(bcm, 0x0024, 0x037E);
787 } else
788 bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
789 bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
790 bcm43xx_write16(bcm, 0x03EC, 0x3F22);
791
792 if (phy->version == 1 && radio->version == 0x2050)
793 bcm43xx_phy_write(bcm, 0x0020, 0x3E1C);
794 else
795 bcm43xx_phy_write(bcm, 0x0020, 0x301C);
796
797 if (phy->version == 0)
798 bcm43xx_write16(bcm, 0x03E4, 0x3000);
799
800 /* Force to channel 7, even if not supported. */
801 bcm43xx_radio_selectchannel(bcm, 7, 0);
802
803 if (radio->version != 0x2050) {
804 bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
805 bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
806 }
807
808 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
809 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
810
811 if (radio->version == 0x2050) {
812 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
813 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
814 }
815
816 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
817 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
818
819 bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007);
820
821 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
822
823 bcm43xx_phy_write(bcm, 0x0014, 0x0080);
824 bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
825 bcm43xx_phy_write(bcm, 0x88A3, 0x002A);
826
827 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
828
829 if (radio->version == 0x2050)
830 bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
831
832 bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004);
833}
834
835static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
836{
837 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
838 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
839 u16 offset, val;
840
841 bcm43xx_phy_write(bcm, 0x003E, 0x817A);
842 bcm43xx_radio_write16(bcm, 0x007A,
843 (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058));
844 if ((radio->manufact == 0x17F) &&
845 (radio->version == 0x2050) &&
846 (radio->revision == 3 ||
847 radio->revision == 4 ||
848 radio->revision == 5)) {
849 bcm43xx_radio_write16(bcm, 0x0051, 0x001F);
850 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
851 bcm43xx_radio_write16(bcm, 0x0053, 0x005B);
852 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
853 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
854 bcm43xx_radio_write16(bcm, 0x005B, 0x0088);
855 bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
856 bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
857 bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
858 }
859 if ((radio->manufact == 0x17F) &&
860 (radio->version == 0x2050) &&
861 (radio->revision == 6)) {
862 bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
863 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
864 bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
865 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
866 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
867 bcm43xx_radio_write16(bcm, 0x005B, 0x008B);
868 bcm43xx_radio_write16(bcm, 0x005C, 0x00B5);
869 bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
870 bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
871 bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
872 bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
873 bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
874 }
875 if ((radio->manufact == 0x17F) &&
876 (radio->version == 0x2050) &&
877 (radio->revision == 7)) {
878 bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
879 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
880 bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
881 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
882 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
883 bcm43xx_radio_write16(bcm, 0x005B, 0x00A8);
884 bcm43xx_radio_write16(bcm, 0x005C, 0x0075);
885 bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
886 bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
887 bcm43xx_radio_write16(bcm, 0x007D, 0x00E8);
888 bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
889 bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
890 bcm43xx_radio_write16(bcm, 0x007B, 0x0000);
891 }
892 if ((radio->manufact == 0x17F) &&
893 (radio->version == 0x2050) &&
894 (radio->revision == 8)) {
895 bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
896 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
897 bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
898 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
899 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
900 bcm43xx_radio_write16(bcm, 0x005B, 0x006B);
901 bcm43xx_radio_write16(bcm, 0x005C, 0x000F);
902 if (bcm->sprom.boardflags & 0x8000) {
903 bcm43xx_radio_write16(bcm, 0x005D, 0x00FA);
904 bcm43xx_radio_write16(bcm, 0x005E, 0x00D8);
905 } else {
906 bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
907 bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
908 }
909 bcm43xx_radio_write16(bcm, 0x0073, 0x0003);
910 bcm43xx_radio_write16(bcm, 0x007D, 0x00A8);
911 bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
912 bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
913 }
914 val = 0x1E1F;
915 for (offset = 0x0088; offset < 0x0098; offset++) {
916 bcm43xx_phy_write(bcm, offset, val);
917 val -= 0x0202;
918 }
919 val = 0x3E3F;
920 for (offset = 0x0098; offset < 0x00A8; offset++) {
921 bcm43xx_phy_write(bcm, offset, val);
922 val -= 0x0202;
923 }
924 val = 0x2120;
925 for (offset = 0x00A8; offset < 0x00C8; offset++) {
926 bcm43xx_phy_write(bcm, offset, (val & 0x3F3F));
927 val += 0x0202;
928 }
929 if (phy->type == BCM43xx_PHYTYPE_G) {
930 bcm43xx_radio_write16(bcm, 0x007A,
931 bcm43xx_radio_read16(bcm, 0x007A) | 0x0020);
932 bcm43xx_radio_write16(bcm, 0x0051,
933 bcm43xx_radio_read16(bcm, 0x0051) | 0x0004);
934 bcm43xx_phy_write(bcm, 0x0802,
935 bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
936 bcm43xx_phy_write(bcm, 0x042B,
937 bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
938 }
939
940 /* Force to channel 7, even if not supported. */
941 bcm43xx_radio_selectchannel(bcm, 7, 0);
942
943 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
944 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
945 udelay(40);
946 bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002));
947 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
948 if ((bcm->current_core->radio->manufact == 0x17F) &&
949 (bcm->current_core->radio->version == 0x2050) &&
950 (bcm->current_core->radio->revision == 2)) {
951 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
952 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
953 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
954 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
955 }
956 bcm43xx_radio_write16(bcm, 0x007A,
957 (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007);
958
959 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
960
961 bcm43xx_phy_write(bcm, 0x0014, 0x0200);
962 if (radio->version == 0x2050){
963 if (radio->revision == 3 ||
964 radio->revision == 4 ||
965 radio->revision == 5)
966 bcm43xx_phy_write(bcm, 0x002A, 0x8AC0);
967 else
968 bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
969 }
970 bcm43xx_phy_write(bcm, 0x0038, 0x0668);
971 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
972 if (radio->version == 0x2050) {
973 if (radio->revision == 3 ||
974 radio->revision == 4 ||
975 radio->revision == 5)
976 bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003);
977 else if (radio->revision <= 2)
978 bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
979 }
980
981 if (phy->rev == 4)
982 bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004);
983 else
984 bcm43xx_write16(bcm, 0x03E4, 0x0009);
985 if (phy->type == BCM43xx_PHYTYPE_B) {
986 bcm43xx_write16(bcm, 0x03E6, 0x8140);
987 bcm43xx_phy_write(bcm, 0x0016, 0x5410);
988 bcm43xx_phy_write(bcm, 0x0017, 0xA820);
989 bcm43xx_phy_write(bcm, 0x0007, 0x0062);
990 TODO();//TODO: calibrate stuff.
991 bcm43xx_phy_init_pctl(bcm);
992 } else
993 bcm43xx_write16(bcm, 0x03E6, 0x0);
994}
995
996static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
997{
998 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
999 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1000 u16 tmp;
1001
1002 if (phy->rev == 1)
1003 bcm43xx_phy_initb5(bcm);
1004 else if (phy->rev >= 2 && phy->rev <= 7)
1005 bcm43xx_phy_initb6(bcm);
1006 if (phy->rev >= 2 || phy->connected)
1007 bcm43xx_phy_inita(bcm);
1008
1009 if (phy->rev >= 2) {
1010 bcm43xx_phy_write(bcm, 0x0814, 0x0000);
1011 bcm43xx_phy_write(bcm, 0x0815, 0x0000);
1012 if (phy->rev == 2)
1013 bcm43xx_phy_write(bcm, 0x0811, 0x0000);
1014 else if (phy->rev >= 3)
1015 bcm43xx_phy_write(bcm, 0x0811, 0x0400);
1016 bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
1017 tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF;
1018 if (tmp == 3) {
1019 bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
1020 bcm43xx_phy_write(bcm, 0x04C3, 0x8606);
1021 } else if (tmp == 4 || tmp == 5) {
1022 bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
1023 bcm43xx_phy_write(bcm, 0x04C3, 0x8006);
1024 bcm43xx_phy_write(bcm, 0x04CC, (bcm43xx_phy_read(bcm, 0x04CC)
1025 & 0x00FF) | 0x1F00);
1026 }
1027 }
1028 if (radio->revision <= 3 && phy->connected)
1029 bcm43xx_phy_write(bcm, 0x047E, 0x0078);
1030 if (radio->revision >= 6 && radio->revision <= 8) {
1031 bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080);
1032 bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004);
1033 }
1034 if (radio->initval == 0xFFFF) {
1035 radio->initval = bcm43xx_radio_init2050(bcm);
1036 bcm43xx_phy_lo_g_measure(bcm);
1037 } else {
1038 bcm43xx_radio_write16(bcm, 0x0078, radio->initval);
1039 bcm43xx_radio_write16(bcm, 0x0052,
1040 (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0)
1041 | radio->txpower[3]);
1042 }
1043
1044 if (phy->connected) {
1045 bcm43xx_phy_lo_adjust(bcm, 0);
1046 bcm43xx_phy_write(bcm, 0x080F, 0x8078);
1047
1048 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
1049 bcm43xx_phy_write(bcm, 0x002E, 0x807F);
1050 else
1051 bcm43xx_phy_write(bcm, 0x002E, 0x8075);
1052
1053 if (phy->rev < 2)
1054 bcm43xx_phy_write(bcm, 0x002F, 0x0101);
1055 else
1056 bcm43xx_phy_write(bcm, 0x002F, 0x0202);
1057 }
1058
1059 if ((bcm->sprom.boardflags & BCM43xx_BFL_RSSI) == 0) {
1060 FIXME();//FIXME: 0x7FFFFFFF should be 16-bit !
1061 bcm43xx_nrssi_hw_update(bcm, (u16)0x7FFFFFFF);
1062 bcm43xx_calc_nrssi_threshold(bcm);
1063 } else if (phy->connected) {
1064 if (radio->nrssi[0] == -1000) {
1065 assert(radio->nrssi[1] == -1000);
1066 bcm43xx_calc_nrssi_slope(bcm);
1067 } else
1068 bcm43xx_calc_nrssi_threshold(bcm);
1069 }
1070 bcm43xx_phy_init_pctl(bcm);
1071}
1072
1073static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
1074{
1075 int i;
1076 u16 ret = 0;
1077
1078 for (i = 0; i < 10; i++){
1079 bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
1080 udelay(1);
1081 bcm43xx_phy_write(bcm, 0x0015, 0xEFA0);
1082 udelay(10);
1083 bcm43xx_phy_write(bcm, 0x0015, 0xFFA0);
1084 udelay(40);
1085 ret += bcm43xx_phy_read(bcm, 0x002C);
1086 }
1087
1088 return ret;
1089}
1090
1091void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm)
1092{
1093 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1094 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1095 u16 regstack[12] = { 0 };
1096 u16 mls;
1097 u16 fval;
1098 int i, j;
1099
1100 regstack[0] = bcm43xx_phy_read(bcm, 0x0015);
1101 regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0;
1102
1103 if (radio->version == 0x2053) {
1104 regstack[2] = bcm43xx_phy_read(bcm, 0x000A);
1105 regstack[3] = bcm43xx_phy_read(bcm, 0x002A);
1106 regstack[4] = bcm43xx_phy_read(bcm, 0x0035);
1107 regstack[5] = bcm43xx_phy_read(bcm, 0x0003);
1108 regstack[6] = bcm43xx_phy_read(bcm, 0x0001);
1109 regstack[7] = bcm43xx_phy_read(bcm, 0x0030);
1110
1111 regstack[8] = bcm43xx_radio_read16(bcm, 0x0043);
1112 regstack[9] = bcm43xx_radio_read16(bcm, 0x007A);
1113 regstack[10] = bcm43xx_read16(bcm, 0x03EC);
1114 regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0;
1115
1116 bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
1117 bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
1118 bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F);
1119 bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0);
1120 }
1121 bcm43xx_phy_write(bcm, 0x0015, 0xB000);
1122 bcm43xx_phy_write(bcm, 0x002B, 0x0004);
1123
1124 if (radio->version == 0x2053) {
1125 bcm43xx_phy_write(bcm, 0x002B, 0x0203);
1126 bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
1127 }
1128
1129 phy->minlowsig[0] = 0xFFFF;
1130
1131 for (i = 0; i < 4; i++) {
1132 bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
1133 bcm43xx_phy_lo_b_r15_loop(bcm);
1134 }
1135 for (i = 0; i < 10; i++) {
1136 bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
1137 mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
1138 if (mls < phy->minlowsig[0]) {
1139 phy->minlowsig[0] = mls;
1140 phy->minlowsigpos[0] = i;
1141 }
1142 }
1143 bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]);
1144
1145 phy->minlowsig[1] = 0xFFFF;
1146
1147 for (i = -4; i < 5; i += 2) {
1148 for (j = -4; j < 5; j += 2) {
1149 if (j < 0)
1150 fval = (0x0100 * i) + j + 0x0100;
1151 else
1152 fval = (0x0100 * i) + j;
1153 bcm43xx_phy_write(bcm, 0x002F, fval);
1154 mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
1155 if (mls < phy->minlowsig[1]) {
1156 phy->minlowsig[1] = mls;
1157 phy->minlowsigpos[1] = fval;
1158 }
1159 }
1160 }
1161 phy->minlowsigpos[1] += 0x0101;
1162
1163 bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]);
1164 if (radio->version == 2053) {
1165 bcm43xx_phy_write(bcm, 0x000A, regstack[2]);
1166 bcm43xx_phy_write(bcm, 0x002A, regstack[3]);
1167 bcm43xx_phy_write(bcm, 0x0035, regstack[4]);
1168 bcm43xx_phy_write(bcm, 0x0003, regstack[5]);
1169 bcm43xx_phy_write(bcm, 0x0001, regstack[6]);
1170 bcm43xx_phy_write(bcm, 0x0030, regstack[7]);
1171
1172 bcm43xx_radio_write16(bcm, 0x0043, regstack[8]);
1173 bcm43xx_radio_write16(bcm, 0x007A, regstack[9]);
1174
1175 bcm43xx_radio_write16(bcm, 0x0052,
1176 (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F)
1177 | regstack[11]);
1178
1179 bcm43xx_write16(bcm, 0x03EC, regstack[10]);
1180 }
1181 bcm43xx_phy_write(bcm, 0x0015, regstack[0]);
1182}
1183
1184static inline
1185u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
1186{
1187 if (bcm->current_core->phy->connected) {
1188 bcm43xx_phy_write(bcm, 0x15, 0xE300);
1189 control <<= 8;
1190 bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0);
1191 udelay(5);
1192 bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2);
1193 udelay(2);
1194 bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3);
1195 udelay(4);
1196 bcm43xx_phy_write(bcm, 0x0015, 0xF300);
1197 udelay(8);
1198 } else {
1199 bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0);
1200 udelay(2);
1201 bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0);
1202 udelay(4);
1203 bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
1204 udelay(8);
1205 }
1206
1207 return bcm43xx_phy_read(bcm, 0x002D);
1208}
1209
1210static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
1211{
1212 int i;
1213 u32 ret = 0;
1214
1215 for (i = 0; i < 8; i++)
1216 ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control);
1217
1218 return ret;
1219}
1220
1221/* Write the LocalOscillator CONTROL */
1222static inline
1223void bcm43xx_lo_write(struct bcm43xx_private *bcm,
1224 struct bcm43xx_lopair *pair)
1225{
1226 u16 value;
1227
1228 value = (u8)(pair->low);
1229 value |= ((u8)(pair->high)) << 8;
1230
1231#ifdef CONFIG_BCM43XX_DEBUG
1232 /* Sanity check. */
1233 if (pair->low < -8 || pair->low > 8 ||
1234 pair->high < -8 || pair->high > 8) {
1235 printk(KERN_WARNING PFX
1236 "WARNING: Writing invalid LOpair "
1237 "(low: %d, high: %d, index: %lu)\n",
1238 pair->low, pair->high,
1239 (unsigned long)(pair - bcm->current_core->phy->_lo_pairs));
1240 dump_stack();
1241 }
1242#endif
1243
1244 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value);
1245}
1246
1247static inline
1248struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm,
1249 u16 baseband_attenuation,
1250 u16 radio_attenuation,
1251 u16 tx)
1252{
1253 static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
1254 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1255
1256 if (baseband_attenuation > 6)
1257 baseband_attenuation = 6;
1258 assert(radio_attenuation < 10);
1259 assert(tx == 0 || tx == 3);
1260
1261 if (tx == 3) {
1262 return bcm43xx_get_lopair(phy,
1263 radio_attenuation,
1264 baseband_attenuation);
1265 }
1266 return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation);
1267}
1268
1269static inline
1270struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm)
1271{
1272 return bcm43xx_find_lopair(bcm,
1273 bcm->current_core->radio->txpower[0],
1274 bcm->current_core->radio->txpower[1],
1275 bcm->current_core->radio->txpower[2]);
1276}
1277
1278/* Adjust B/G LO */
1279void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed)
1280{
1281 struct bcm43xx_lopair *pair;
1282
1283 if (fixed) {
1284 /* Use fixed values. Only for initialization. */
1285 pair = bcm43xx_find_lopair(bcm, 2, 3, 0);
1286 } else
1287 pair = bcm43xx_current_lopair(bcm);
1288 bcm43xx_lo_write(bcm, pair);
1289}
1290
1291static inline
1292void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm)
1293{
1294 u16 txctl2 = 0, i;
1295 u32 smallest, tmp;
1296
1297 bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
1298 udelay(10);
1299 smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
1300 for (i = 0; i < 16; i++) {
1301 bcm43xx_radio_write16(bcm, 0x0052, i);
1302 udelay(10);
1303 tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
1304 if (tmp < smallest) {
1305 smallest = tmp;
1306 txctl2 = i;
1307 }
1308 }
1309 bcm->current_core->radio->txpower[3] = txctl2;
1310}
1311
1312static
1313void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm,
1314 const struct bcm43xx_lopair *in_pair,
1315 struct bcm43xx_lopair *out_pair,
1316 u16 r27)
1317{
1318 static const struct bcm43xx_lopair transitions[8] = {
1319 { .high = 1, .low = 1, },
1320 { .high = 1, .low = 0, },
1321 { .high = 1, .low = -1, },
1322 { .high = 0, .low = -1, },
1323 { .high = -1, .low = -1, },
1324 { .high = -1, .low = 0, },
1325 { .high = -1, .low = 1, },
1326 { .high = 0, .low = 1, },
1327 };
1328 struct bcm43xx_lopair lowest_transition = {
1329 .high = in_pair->high,
1330 .low = in_pair->low,
1331 };
1332 struct bcm43xx_lopair tmp_pair;
1333 struct bcm43xx_lopair transition;
1334 int i = 12;
1335 int state = 0;
1336 int found_lower;
1337 int j, begin, end;
1338 u32 lowest_deviation;
1339 u32 tmp;
1340
1341 /* Note that in_pair and out_pair can point to the same pair. Be careful. */
1342
1343 bcm43xx_lo_write(bcm, &lowest_transition);
1344 lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
1345 do {
1346 found_lower = 0;
1347 assert(state >= 0 && state <= 8);
1348 if (state == 0) {
1349 begin = 1;
1350 end = 8;
1351 } else if (state % 2 == 0) {
1352 begin = state - 1;
1353 end = state + 1;
1354 } else {
1355 begin = state - 2;
1356 end = state + 2;
1357 }
1358 if (begin < 1)
1359 begin += 8;
1360 if (end > 8)
1361 end -= 8;
1362
1363 j = begin;
1364 tmp_pair.high = lowest_transition.high;
1365 tmp_pair.low = lowest_transition.low;
1366 while (1) {
1367 assert(j >= 1 && j <= 8);
1368 transition.high = tmp_pair.high + transitions[j - 1].high;
1369 transition.low = tmp_pair.low + transitions[j - 1].low;
1370 if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) {
1371 bcm43xx_lo_write(bcm, &transition);
1372 tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
1373 if (tmp < lowest_deviation) {
1374 lowest_deviation = tmp;
1375 state = j;
1376 found_lower = 1;
1377
1378 lowest_transition.high = transition.high;
1379 lowest_transition.low = transition.low;
1380 }
1381 }
1382 if (j == end)
1383 break;
1384 if (j == 8)
1385 j = 1;
1386 else
1387 j++;
1388 }
1389 } while (i-- && found_lower);
1390
1391 out_pair->high = lowest_transition.high;
1392 out_pair->low = lowest_transition.low;
1393}
1394
1395/* Set the baseband attenuation value on chip. */
1396void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
1397 u16 baseband_attenuation)
1398{
1399 u16 value;
1400
1401 if (bcm->current_core->phy->version == 0) {
1402 value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0);
1403 value |= (baseband_attenuation & 0x000F);
1404 bcm43xx_write16(bcm, 0x03E6, value);
1405 return;
1406 }
1407
1408 if (bcm->current_core->phy->version > 1) {
1409 value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
1410 value |= (baseband_attenuation << 2) & 0x003C;
1411 } else {
1412 value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078;
1413 value |= (baseband_attenuation << 3) & 0x0078;
1414 }
1415 bcm43xx_phy_write(bcm, 0x0060, value);
1416}
1417
1418/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
1419void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
1420{
1421 static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
1422 const int is_initializing = bcm43xx_is_initializing(bcm);
1423 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1424 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1425 u16 h, i, oldi = 0, j;
1426 struct bcm43xx_lopair control;
1427 struct bcm43xx_lopair *tmp_control;
1428 u16 tmp;
1429 u16 regstack[16] = { 0 };
1430 u8 oldchannel;
1431
1432 //XXX: What are these?
1433 u8 r27 = 0, r31;
1434
1435 oldchannel = radio->channel;
1436 /* Setup */
1437 if (phy->connected) {
1438 regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
1439 regstack[1] = bcm43xx_phy_read(bcm, 0x0802);
1440 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
1441 bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
1442 }
1443 regstack[3] = bcm43xx_read16(bcm, 0x03E2);
1444 bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000);
1445 regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
1446 regstack[5] = bcm43xx_phy_read(bcm, 0x15);
1447 regstack[6] = bcm43xx_phy_read(bcm, 0x2A);
1448 regstack[7] = bcm43xx_phy_read(bcm, 0x35);
1449 regstack[8] = bcm43xx_phy_read(bcm, 0x60);
1450 regstack[9] = bcm43xx_radio_read16(bcm, 0x43);
1451 regstack[10] = bcm43xx_radio_read16(bcm, 0x7A);
1452 regstack[11] = bcm43xx_radio_read16(bcm, 0x52);
1453 if (phy->connected) {
1454 regstack[12] = bcm43xx_phy_read(bcm, 0x0811);
1455 regstack[13] = bcm43xx_phy_read(bcm, 0x0812);
1456 regstack[14] = bcm43xx_phy_read(bcm, 0x0814);
1457 regstack[15] = bcm43xx_phy_read(bcm, 0x0815);
1458 }
1459 bcm43xx_radio_selectchannel(bcm, 6, 0);
1460 if (phy->connected) {
1461 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
1462 bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
1463 bcm43xx_dummy_transmission(bcm);
1464 }
1465 bcm43xx_radio_write16(bcm, 0x0043, 0x0006);
1466
1467 bcm43xx_phy_set_baseband_attenuation(bcm, 2);
1468
1469 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000);
1470 bcm43xx_phy_write(bcm, 0x002E, 0x007F);
1471 bcm43xx_phy_write(bcm, 0x080F, 0x0078);
1472 bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7));
1473 bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0);
1474 bcm43xx_phy_write(bcm, 0x002B, 0x0203);
1475 bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
1476 if (phy->connected) {
1477 bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003);
1478 bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC);
1479 bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
1480 bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
1481 }
1482 if (is_initializing)
1483 bcm43xx_phy_lo_g_measure_txctl2(bcm);
1484 bcm43xx_phy_write(bcm, 0x080F, 0x8078);
1485
1486 /* Measure */
1487 control.low = 0;
1488 control.high = 0;
1489 for (h = 0; h < 10; h++) {
1490 /* Loop over each possible RadioAttenuation (0-9) */
1491 i = pairorder[h];
1492 if (is_initializing) {
1493 if (i == 3) {
1494 control.low = 0;
1495 control.high = 0;
1496 } else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
1497 ((i % 2 == 0) && (oldi % 2 == 0))) {
1498 tmp_control = bcm43xx_get_lopair(phy, oldi, 0);
1499 memcpy(&control, tmp_control, sizeof(control));
1500 } else {
1501 tmp_control = bcm43xx_get_lopair(phy, 3, 0);
1502 memcpy(&control, tmp_control, sizeof(control));
1503 }
1504 }
1505 /* Loop over each possible BasebandAttenuation/2 */
1506 for (j = 0; j < 4; j++) {
1507 if (is_initializing) {
1508 tmp = i * 2 + j;
1509 r27 = 0;
1510 r31 = 0;
1511 if (tmp > 14) {
1512 r31 = 1;
1513 if (tmp > 17)
1514 r27 = 1;
1515 if (tmp > 19)
1516 r27 = 2;
1517 }
1518 } else {
1519 tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
1520 if (!tmp_control->used)
1521 continue;
1522 memcpy(&control, tmp_control, sizeof(control));
1523 r27 = 3;
1524 r31 = 0;
1525 }
1526 bcm43xx_radio_write16(bcm, 0x43, i);
1527 bcm43xx_radio_write16(bcm, 0x52,
1528 radio->txpower[3]);
1529 udelay(10);
1530
1531 bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
1532
1533 tmp = (regstack[10] & 0xFFF0);
1534 if (r31)
1535 tmp |= 0x0008;
1536 bcm43xx_radio_write16(bcm, 0x007A, tmp);
1537
1538 tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
1539 bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
1540 }
1541 oldi = i;
1542 }
1543 /* Loop over each possible RadioAttenuation (10-13) */
1544 for (i = 10; i < 14; i++) {
1545 /* Loop over each possible BasebandAttenuation/2 */
1546 for (j = 0; j < 4; j++) {
1547 if (is_initializing) {
1548 tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
1549 memcpy(&control, tmp_control, sizeof(control));
1550 tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger.
1551 r27 = 0;
1552 r31 = 0;
1553 if (tmp > 14) {
1554 r31 = 1;
1555 if (tmp > 17)
1556 r27 = 1;
1557 if (tmp > 19)
1558 r27 = 2;
1559 }
1560 } else {
1561 tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
1562 if (!tmp_control->used)
1563 continue;
1564 memcpy(&control, tmp_control, sizeof(control));
1565 r27 = 3;
1566 r31 = 0;
1567 }
1568 bcm43xx_radio_write16(bcm, 0x43, i - 9);
1569 bcm43xx_radio_write16(bcm, 0x52,
1570 radio->txpower[3]
1571 | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
1572 udelay(10);
1573
1574 bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
1575
1576 tmp = (regstack[10] & 0xFFF0);
1577 if (r31)
1578 tmp |= 0x0008;
1579 bcm43xx_radio_write16(bcm, 0x7A, tmp);
1580
1581 tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
1582 bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
1583 }
1584 }
1585
1586 /* Restoration */
1587 if (phy->connected) {
1588 bcm43xx_phy_write(bcm, 0x0015, 0xE300);
1589 bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0);
1590 udelay(5);
1591 bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
1592 udelay(2);
1593 bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
1594 } else
1595 bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
1596 bcm43xx_phy_lo_adjust(bcm, is_initializing);
1597 bcm43xx_phy_write(bcm, 0x002E, 0x807F);
1598 if (phy->connected)
1599 bcm43xx_phy_write(bcm, 0x002F, 0x0202);
1600 else
1601 bcm43xx_phy_write(bcm, 0x002F, 0x0101);
1602 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]);
1603 bcm43xx_phy_write(bcm, 0x0015, regstack[5]);
1604 bcm43xx_phy_write(bcm, 0x002A, regstack[6]);
1605 bcm43xx_phy_write(bcm, 0x0035, regstack[7]);
1606 bcm43xx_phy_write(bcm, 0x0060, regstack[8]);
1607 bcm43xx_radio_write16(bcm, 0x0043, regstack[9]);
1608 bcm43xx_radio_write16(bcm, 0x007A, regstack[10]);
1609 regstack[11] &= 0x00F0;
1610 regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F);
1611 bcm43xx_radio_write16(bcm, 0x52, regstack[11]);
1612 bcm43xx_write16(bcm, 0x03E2, regstack[3]);
1613 if (phy->connected) {
1614 bcm43xx_phy_write(bcm, 0x0811, regstack[12]);
1615 bcm43xx_phy_write(bcm, 0x0812, regstack[13]);
1616 bcm43xx_phy_write(bcm, 0x0814, regstack[14]);
1617 bcm43xx_phy_write(bcm, 0x0815, regstack[15]);
1618 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]);
1619 bcm43xx_phy_write(bcm, 0x0802, regstack[1]);
1620 }
1621 bcm43xx_radio_selectchannel(bcm, oldchannel, 1);
1622
1623#ifdef CONFIG_BCM43XX_DEBUG
1624 {
1625 /* Sanity check for all lopairs. */
1626 for (i = 0; i < BCM43xx_LO_COUNT; i++) {
1627 tmp_control = phy->_lo_pairs + i;
1628 if (tmp_control->low < -8 || tmp_control->low > 8 ||
1629 tmp_control->high < -8 || tmp_control->high > 8) {
1630 printk(KERN_WARNING PFX
1631 "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n",
1632 tmp_control->low, tmp_control->high, i);
1633 }
1634 }
1635 }
1636#endif /* CONFIG_BCM43XX_DEBUG */
1637}
1638
1639static
1640void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm)
1641{
1642 struct bcm43xx_lopair *pair;
1643
1644 pair = bcm43xx_current_lopair(bcm);
1645 pair->used = 1;
1646}
1647
1648void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm)
1649{
1650 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1651 struct bcm43xx_lopair *pair;
1652 int i;
1653
1654 for (i = 0; i < BCM43xx_LO_COUNT; i++) {
1655 pair = phy->_lo_pairs + i;
1656 pair->used = 0;
1657 }
1658}
1659
1660/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
1661 * This function converts a TSSI value to dBm in Q5.2
1662 */
1663static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi)
1664{
1665 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1666 s8 dbm = 0;
1667 s32 tmp;
1668
1669 tmp = phy->idle_tssi;
1670 tmp += tssi;
1671 tmp -= phy->savedpctlreg;
1672
1673 switch (phy->type) {
1674 case BCM43xx_PHYTYPE_A:
1675 tmp += 0x80;
1676 tmp = limit_value(tmp, 0x00, 0xFF);
1677 dbm = phy->tssi2dbm[tmp];
1678 TODO(); //TODO: There's a FIXME on the specs
1679 break;
1680 case BCM43xx_PHYTYPE_B:
1681 case BCM43xx_PHYTYPE_G:
1682 tmp = limit_value(tmp, 0x00, 0x3F);
1683 dbm = phy->tssi2dbm[tmp];
1684 break;
1685 default:
1686 assert(0);
1687 }
1688
1689 return dbm;
1690}
1691
1692/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
1693void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm)
1694{
1695 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1696 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1697
1698 if (phy->savedpctlreg == 0xFFFF)
1699 return;
1700 if ((bcm->board_type == 0x0416) &&
1701 (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM))
1702 return;
1703
1704 switch (phy->type) {
1705 case BCM43xx_PHYTYPE_A: {
1706
1707 TODO(); //TODO: Nothing for A PHYs yet :-/
1708
1709 break;
1710 }
1711 case BCM43xx_PHYTYPE_B:
1712 case BCM43xx_PHYTYPE_G: {
1713 u16 tmp;
1714 u16 txpower;
1715 s8 v0, v1, v2, v3;
1716 s8 average;
1717 u8 max_pwr;
1718 s16 desired_pwr, estimated_pwr, pwr_adjust;
1719 s16 radio_att_delta, baseband_att_delta;
1720 s16 radio_attenuation, baseband_attenuation;
1721 unsigned long phylock_flags;
1722
1723 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058);
1724 v0 = (s8)(tmp & 0x00FF);
1725 v1 = (s8)((tmp & 0xFF00) >> 8);
1726 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A);
1727 v2 = (s8)(tmp & 0x00FF);
1728 v3 = (s8)((tmp & 0xFF00) >> 8);
1729 tmp = 0;
1730
1731 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
1732 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070);
1733 v0 = (s8)(tmp & 0x00FF);
1734 v1 = (s8)((tmp & 0xFF00) >> 8);
1735 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072);
1736 v2 = (s8)(tmp & 0x00FF);
1737 v3 = (s8)((tmp & 0xFF00) >> 8);
1738 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
1739 return;
1740 v0 = (v0 + 0x20) & 0x3F;
1741 v1 = (v1 + 0x20) & 0x3F;
1742 v2 = (v2 + 0x20) & 0x3F;
1743 v3 = (v3 + 0x20) & 0x3F;
1744 tmp = 1;
1745 }
1746 bcm43xx_radio_clear_tssi(bcm);
1747
1748 average = (v0 + v1 + v2 + v3 + 2) / 4;
1749
1750 if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8))
1751 average -= 13;
1752
1753 estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average);
1754
1755 max_pwr = bcm->sprom.maxpower_bgphy;
1756
1757 if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) &&
1758 (phy->type == BCM43xx_PHYTYPE_G))
1759 max_pwr -= 0x3;
1760
1761 /*TODO:
1762 max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr)
1763 where REG is the max power as per the regulatory domain
1764 */
1765
1766 /*TODO: Get desired_pwr from wx_handlers or the stack
1767 limit_value(desired_pwr, 0, max_pwr);
1768 */
1769
1770 desired_pwr = max_pwr; /* remove this when we have a real desired_pwr */
1771
1772 pwr_adjust = desired_pwr - estimated_pwr;
1773
1774 radio_att_delta = -(pwr_adjust + 7) >> 3;
1775 baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
1776 if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
1777 bcm43xx_phy_lo_mark_current_used(bcm);
1778 return;
1779 }
1780
1781 /* Calculate the new attenuation values. */
1782 baseband_attenuation = radio->txpower[0];
1783 baseband_attenuation += baseband_att_delta;
1784 radio_attenuation = radio->txpower[1];
1785 radio_attenuation += radio_att_delta;
1786
1787 /* Get baseband and radio attenuation values into their permitted ranges.
1788 * baseband 0-11, radio 0-9.
1789 * Radio attenuation affects power level 4 times as much as baseband.
1790 */
1791 if (radio_attenuation < 0) {
1792 baseband_attenuation -= (4 * -radio_attenuation);
1793 radio_attenuation = 0;
1794 } else if (radio_attenuation > 9) {
1795 baseband_attenuation += (4 * (radio_attenuation - 9));
1796 radio_attenuation = 9;
1797 } else {
1798 while (baseband_attenuation < 0 && radio_attenuation > 0) {
1799 baseband_attenuation += 4;
1800 radio_attenuation--;
1801 }
1802 while (baseband_attenuation > 11 && radio_attenuation < 9) {
1803 baseband_attenuation -= 4;
1804 radio_attenuation++;
1805 }
1806 }
1807 baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
1808
1809 txpower = radio->txpower[2];
1810 if ((radio->version == 0x2050) && (radio->revision == 2)) {
1811 if (radio_attenuation <= 1) {
1812 if (txpower == 0) {
1813 txpower = 3;
1814 radio_attenuation += 2;
1815 baseband_attenuation += 2;
1816 } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
1817 baseband_attenuation += 4 * (radio_attenuation - 2);
1818 radio_attenuation = 2;
1819 }
1820 } else if (radio_attenuation > 4 && txpower != 0) {
1821 txpower = 0;
1822 if (baseband_attenuation < 3) {
1823 radio_attenuation -= 3;
1824 baseband_attenuation += 2;
1825 } else {
1826 radio_attenuation -= 2;
1827 baseband_attenuation -= 2;
1828 }
1829 }
1830 }
1831 radio->txpower[2] = txpower;
1832 baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
1833 radio_attenuation = limit_value(radio_attenuation, 0, 9);
1834
1835 bcm43xx_phy_lock(bcm, phylock_flags);
1836 bcm43xx_radio_lock(bcm);
1837 bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation,
1838 radio_attenuation, txpower);
1839 bcm43xx_phy_lo_mark_current_used(bcm);
1840 bcm43xx_radio_unlock(bcm);
1841 bcm43xx_phy_unlock(bcm, phylock_flags);
1842 break;
1843 }
1844 default:
1845 assert(0);
1846 }
1847}
1848
1849static inline
1850s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den)
1851{
1852 if (num < 0)
1853 return num/den;
1854 else
1855 return (num+den/2)/den;
1856}
1857
1858static inline
1859s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
1860{
1861 s32 m1, m2, f = 256, q, delta;
1862 s8 i = 0;
1863
1864 m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
1865 m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1);
1866 do {
1867 if (i > 15)
1868 return -EINVAL;
1869 q = bcm43xx_tssi2dbm_ad(f * 4096 -
1870 bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048);
1871 delta = abs(q - f);
1872 f = q;
1873 i++;
1874 } while (delta >= 2);
1875 entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128);
1876 return 0;
1877}
1878
1879/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
1880int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm)
1881{
1882 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1883 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1884 s16 pab0, pab1, pab2;
1885 u8 idx;
1886 s8 *dyn_tssi2dbm;
1887
1888 if (phy->type == BCM43xx_PHYTYPE_A) {
1889 pab0 = (s16)(bcm->sprom.pa1b0);
1890 pab1 = (s16)(bcm->sprom.pa1b1);
1891 pab2 = (s16)(bcm->sprom.pa1b2);
1892 } else {
1893 pab0 = (s16)(bcm->sprom.pa0b0);
1894 pab1 = (s16)(bcm->sprom.pa0b1);
1895 pab2 = (s16)(bcm->sprom.pa0b2);
1896 }
1897
1898 if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) {
1899 phy->idle_tssi = 0x34;
1900 phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
1901 return 0;
1902 }
1903
1904 if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
1905 pab0 != -1 && pab1 != -1 && pab2 != -1) {
1906 /* The pabX values are set in SPROM. Use them. */
1907 if (phy->type == BCM43xx_PHYTYPE_A) {
1908 if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 &&
1909 (s8)bcm->sprom.idle_tssi_tgt_aphy != -1)
1910 phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy);
1911 else
1912 phy->idle_tssi = 62;
1913 } else {
1914 if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 &&
1915 (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1)
1916 phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy);
1917 else
1918 phy->idle_tssi = 62;
1919 }
1920 dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
1921 if (dyn_tssi2dbm == NULL) {
1922 printk(KERN_ERR PFX "Could not allocate memory"
1923 "for tssi2dbm table\n");
1924 return -ENOMEM;
1925 }
1926 for (idx = 0; idx < 64; idx++)
1927 if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
1928 phy->tssi2dbm = NULL;
1929 printk(KERN_ERR PFX "Could not generate "
1930 "tssi2dBm table\n");
1931 return -ENODEV;
1932 }
1933 phy->tssi2dbm = dyn_tssi2dbm;
1934 phy->dyn_tssi_tbl = 1;
1935 } else {
1936 /* pabX values not set in SPROM. */
1937 switch (phy->type) {
1938 case BCM43xx_PHYTYPE_A:
1939 /* APHY needs a generated table. */
1940 phy->tssi2dbm = NULL;
1941 printk(KERN_ERR PFX "Could not generate tssi2dBm "
1942 "table (wrong SPROM info)!\n");
1943 return -ENODEV;
1944 case BCM43xx_PHYTYPE_B:
1945 phy->idle_tssi = 0x34;
1946 phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
1947 break;
1948 case BCM43xx_PHYTYPE_G:
1949 phy->idle_tssi = 0x34;
1950 phy->tssi2dbm = bcm43xx_tssi2dbm_g_table;
1951 break;
1952 }
1953 }
1954
1955 return 0;
1956}
1957
1958int bcm43xx_phy_init(struct bcm43xx_private *bcm)
1959{
1960 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1961 int err = -ENODEV;
1962 unsigned long flags;
1963
1964 /* We do not want to be preempted while calibrating
1965 * the hardware.
1966 */
1967 local_irq_save(flags);
1968
1969 switch (phy->type) {
1970 case BCM43xx_PHYTYPE_A:
1971 if (phy->rev == 2 || phy->rev == 3) {
1972 bcm43xx_phy_inita(bcm);
1973 err = 0;
1974 }
1975 break;
1976 case BCM43xx_PHYTYPE_B:
1977 switch (phy->rev) {
1978 case 2:
1979 bcm43xx_phy_initb2(bcm);
1980 err = 0;
1981 break;
1982 case 4:
1983 bcm43xx_phy_initb4(bcm);
1984 err = 0;
1985 break;
1986 case 5:
1987 bcm43xx_phy_initb5(bcm);
1988 err = 0;
1989 break;
1990 case 6:
1991 bcm43xx_phy_initb6(bcm);
1992 err = 0;
1993 break;
1994 }
1995 break;
1996 case BCM43xx_PHYTYPE_G:
1997 bcm43xx_phy_initg(bcm);
1998 err = 0;
1999 break;
2000 }
2001 local_irq_restore(flags);
2002 if (err)
2003 printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
2004
2005 return err;
2006}
2007
2008void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm)
2009{
2010 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
2011 u16 antennadiv;
2012 u16 offset;
2013 u16 value;
2014 u32 ucodeflags;
2015
2016 antennadiv = phy->antenna_diversity;
2017
2018 if (antennadiv == 0xFFFF)
2019 antennadiv = 3;
2020 assert(antennadiv <= 3);
2021
2022 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2023 BCM43xx_UCODEFLAGS_OFFSET);
2024 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2025 BCM43xx_UCODEFLAGS_OFFSET,
2026 ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV);
2027
2028 switch (phy->type) {
2029 case BCM43xx_PHYTYPE_A:
2030 case BCM43xx_PHYTYPE_G:
2031 if (phy->type == BCM43xx_PHYTYPE_A)
2032 offset = 0x0000;
2033 else
2034 offset = 0x0400;
2035
2036 if (antennadiv == 2)
2037 value = (3/*automatic*/ << 7);
2038 else
2039 value = (antennadiv << 7);
2040 bcm43xx_phy_write(bcm, offset + 1,
2041 (bcm43xx_phy_read(bcm, offset + 1)
2042 & 0x7E7F) | value);
2043
2044 if (antennadiv >= 2) {
2045 if (antennadiv == 2)
2046 value = (antennadiv << 7);
2047 else
2048 value = (0/*force0*/ << 7);
2049 bcm43xx_phy_write(bcm, offset + 0x2B,
2050 (bcm43xx_phy_read(bcm, offset + 0x2B)
2051 & 0xFEFF) | value);
2052 }
2053
2054 if (phy->type == BCM43xx_PHYTYPE_G) {
2055 if (antennadiv >= 2)
2056 bcm43xx_phy_write(bcm, 0x048C,
2057 bcm43xx_phy_read(bcm, 0x048C)
2058 | 0x2000);
2059 else
2060 bcm43xx_phy_write(bcm, 0x048C,
2061 bcm43xx_phy_read(bcm, 0x048C)
2062 & ~0x2000);
2063 if (phy->rev >= 2) {
2064 bcm43xx_phy_write(bcm, 0x0461,
2065 bcm43xx_phy_read(bcm, 0x0461)
2066 | 0x0010);
2067 bcm43xx_phy_write(bcm, 0x04AD,
2068 (bcm43xx_phy_read(bcm, 0x04AD)
2069 & 0x00FF) | 0x0015);
2070 if (phy->rev == 2)
2071 bcm43xx_phy_write(bcm, 0x0427, 0x0008);
2072 else
2073 bcm43xx_phy_write(bcm, 0x0427,
2074 (bcm43xx_phy_read(bcm, 0x0427)
2075 & 0x00FF) | 0x0008);
2076 }
2077 else if (phy->rev >= 6)
2078 bcm43xx_phy_write(bcm, 0x049B, 0x00DC);
2079 } else {
2080 if (phy->rev < 3)
2081 bcm43xx_phy_write(bcm, 0x002B,
2082 (bcm43xx_phy_read(bcm, 0x002B)
2083 & 0x00FF) | 0x0024);
2084 else {
2085 bcm43xx_phy_write(bcm, 0x0061,
2086 bcm43xx_phy_read(bcm, 0x0061)
2087 | 0x0010);
2088 if (phy->rev == 3) {
2089 bcm43xx_phy_write(bcm, 0x0093, 0x001D);
2090 bcm43xx_phy_write(bcm, 0x0027, 0x0008);
2091 } else {
2092 bcm43xx_phy_write(bcm, 0x0093, 0x003A);
2093 bcm43xx_phy_write(bcm, 0x0027,
2094 (bcm43xx_phy_read(bcm, 0x0027)
2095 & 0x00FF) | 0x0008);
2096 }
2097 }
2098 }
2099 break;
2100 case BCM43xx_PHYTYPE_B:
2101 if (bcm->current_core->rev == 2)
2102 value = (3/*automatic*/ << 7);
2103 else
2104 value = (antennadiv << 7);
2105 bcm43xx_phy_write(bcm, 0x03E2,
2106 (bcm43xx_phy_read(bcm, 0x03E2)
2107 & 0xFE7F) | value);
2108 break;
2109 default:
2110 assert(0);
2111 }
2112
2113 if (antennadiv >= 2) {
2114 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2115 BCM43xx_UCODEFLAGS_OFFSET);
2116 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2117 BCM43xx_UCODEFLAGS_OFFSET,
2118 ucodeflags | BCM43xx_UCODEFLAG_AUTODIV);
2119 }
2120
2121 phy->antenna_diversity = antennadiv;
2122}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
new file mode 100644
index 000000000000..1f321ef42be8
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
@@ -0,0 +1,74 @@
1/*
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#ifndef BCM43xx_PHY_H_
32#define BCM43xx_PHY_H_
33
34#include <linux/types.h>
35
36struct bcm43xx_private;
37
38void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm);
39#define bcm43xx_phy_lock(bcm, flags) \
40 do { \
41 local_irq_save(flags); \
42 bcm43xx_raw_phy_lock(bcm); \
43 } while (0)
44void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
45#define bcm43xx_phy_unlock(bcm, flags) \
46 do { \
47 bcm43xx_raw_phy_unlock(bcm); \
48 local_irq_restore(flags); \
49 } while (0)
50
51u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
52void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
53
54int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm);
55int bcm43xx_phy_init(struct bcm43xx_private *bcm);
56
57void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm);
58void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm);
59int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect);
60
61void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm);
62void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm);
63void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm);
64
65/* Adjust the LocalOscillator to the saved values.
66 * "fixed" is only set to 1 once in initialization. Set to 0 otherwise.
67 */
68void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed);
69void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm);
70
71void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
72 u16 baseband_attenuation);
73
74#endif /* BCM43xx_PHY_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
new file mode 100644
index 000000000000..9a55e9d00528
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -0,0 +1,592 @@
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 PIO Transmission
6
7 Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23
24*/
25
26#include "bcm43xx.h"
27#include "bcm43xx_pio.h"
28#include "bcm43xx_main.h"
29
30#include <linux/delay.h>
31
32
33static inline
34u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue,
35 u16 offset)
36{
37 return bcm43xx_read16(queue->bcm, queue->mmio_base + offset);
38}
39
40static inline
41void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
42 u16 offset, u16 value)
43{
44 bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
45}
46
47static inline
48void tx_start(struct bcm43xx_pioqueue *queue)
49{
50 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_INIT);
51}
52
53static inline
54void tx_octet(struct bcm43xx_pioqueue *queue,
55 u8 octet)
56{
57 if (queue->bcm->current_core->rev < 3) {
58 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet);
59 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI);
60 } else {
61 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI);
62 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet);
63 }
64}
65
66static inline
67void tx_data(struct bcm43xx_pioqueue *queue,
68 u8 *packet,
69 unsigned int octets)
70{
71 u16 data;
72 unsigned int i = 0;
73
74 if (queue->bcm->current_core->rev < 3) {
75 data = be16_to_cpu( *((u16 *)packet) );
76 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
77 i += 2;
78 }
79 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
80 BCM43xx_PIO_TXCTL_WRITELO | BCM43xx_PIO_TXCTL_WRITEHI);
81 for ( ; i < octets - 1; i += 2) {
82 data = be16_to_cpu( *((u16 *)(packet + i)) );
83 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
84 }
85 if (octets % 2)
86 tx_octet(queue, packet[octets - 1]);
87}
88
89static inline
90void tx_complete(struct bcm43xx_pioqueue *queue,
91 struct sk_buff *skb)
92{
93 u16 data;
94
95 if (queue->bcm->current_core->rev < 3) {
96 data = be16_to_cpu( *((u16 *)(skb->data + skb->len - 2)) );
97 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
98 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
99 BCM43xx_PIO_TXCTL_WRITEHI | BCM43xx_PIO_TXCTL_COMPLETE);
100 } else {
101 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_COMPLETE);
102 }
103}
104
105static inline
106u16 generate_cookie(struct bcm43xx_pioqueue *queue,
107 int packetindex)
108{
109 u16 cookie = 0x0000;
110
111 /* We use the upper 4 bits for the PIO
112 * controller ID and the lower 12 bits
113 * for the packet index (in the cache).
114 */
115 switch (queue->mmio_base) {
116 default:
117 assert(0);
118 case BCM43xx_MMIO_PIO1_BASE:
119 break;
120 case BCM43xx_MMIO_PIO2_BASE:
121 cookie = 0x1000;
122 break;
123 case BCM43xx_MMIO_PIO3_BASE:
124 cookie = 0x2000;
125 break;
126 case BCM43xx_MMIO_PIO4_BASE:
127 cookie = 0x3000;
128 break;
129 }
130 assert(((u16)packetindex & 0xF000) == 0x0000);
131 cookie |= (u16)packetindex;
132
133 return cookie;
134}
135
136static inline
137struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm,
138 u16 cookie,
139 struct bcm43xx_pio_txpacket **packet)
140{
141 struct bcm43xx_pioqueue *queue = NULL;
142 int packetindex;
143
144 switch (cookie & 0xF000) {
145 case 0x0000:
146 queue = bcm->current_core->pio->queue0;
147 break;
148 case 0x1000:
149 queue = bcm->current_core->pio->queue1;
150 break;
151 case 0x2000:
152 queue = bcm->current_core->pio->queue2;
153 break;
154 case 0x3000:
155 queue = bcm->current_core->pio->queue3;
156 break;
157 default:
158 assert(0);
159 }
160
161 packetindex = (cookie & 0x0FFF);
162 assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS);
163 *packet = queue->__tx_packets_cache + packetindex;
164
165 return queue;
166}
167
168static inline
169void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
170 struct sk_buff *skb,
171 struct bcm43xx_pio_txpacket *packet)
172{
173 unsigned int octets;
174
175 assert(skb_shinfo(skb)->nr_frags == 0);
176 assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
177
178 __skb_push(skb, sizeof(struct bcm43xx_txhdr));
179 bcm43xx_generate_txhdr(queue->bcm,
180 (struct bcm43xx_txhdr *)skb->data,
181 skb->data + sizeof(struct bcm43xx_txhdr),
182 skb->len - sizeof(struct bcm43xx_txhdr),
183 (packet->xmitted_frags == 0),
184 generate_cookie(queue, pio_txpacket_getindex(packet)));
185
186 tx_start(queue);
187 octets = skb->len;
188 if (queue->bcm->current_core->rev < 3) //FIXME: && this is the last packet in the queue.
189 octets -= 2;
190 tx_data(queue, (u8 *)skb->data, octets);
191 tx_complete(queue, skb);
192}
193
194static inline
195int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
196{
197 struct bcm43xx_pioqueue *queue = packet->queue;
198 struct ieee80211_txb *txb = packet->txb;
199 struct sk_buff *skb;
200 u16 octets;
201 int i;
202
203 for (i = packet->xmitted_frags; i < txb->nr_frags; i++) {
204 skb = txb->fragments[i];
205
206 octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr);
207
208 assert(queue->tx_devq_size >= octets);
209 assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS);
210 assert(queue->tx_devq_used <= queue->tx_devq_size);
211 /* Check if there is sufficient free space on the device
212 * TX queue. If not, return and let the TX-work-handler
213 * retry later.
214 */
215 if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS)
216 return -EBUSY;
217 if (queue->tx_devq_used + octets > queue->tx_devq_size)
218 return -EBUSY;
219 /* Now poke the device. */
220 pio_tx_write_fragment(queue, skb, packet);
221
222 /* Account for the packet size.
223 * (We must not overflow the device TX queue)
224 */
225 queue->tx_devq_packets++;
226 queue->tx_devq_used += octets;
227
228 assert(packet->xmitted_frags <= packet->txb->nr_frags);
229 packet->xmitted_frags++;
230 packet->xmitted_octets += octets;
231 }
232 list_move_tail(&packet->list, &queue->txrunning);
233
234 return 0;
235}
236
237static void free_txpacket(struct bcm43xx_pio_txpacket *packet)
238{
239 struct bcm43xx_pioqueue *queue = packet->queue;
240
241 ieee80211_txb_free(packet->txb);
242
243 list_move(&packet->list, &packet->queue->txfree);
244
245 assert(queue->tx_devq_used >= packet->xmitted_octets);
246 queue->tx_devq_used -= packet->xmitted_octets;
247 assert(queue->tx_devq_packets >= packet->xmitted_frags);
248 queue->tx_devq_packets -= packet->xmitted_frags;
249}
250
251static void txwork_handler(void *d)
252{
253 struct bcm43xx_pioqueue *queue = d;
254 unsigned long flags;
255 struct bcm43xx_pio_txpacket *packet, *tmp_packet;
256 int err;
257
258 spin_lock_irqsave(&queue->txlock, flags);
259 list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
260 assert(packet->xmitted_frags < packet->txb->nr_frags);
261 if (packet->xmitted_frags == 0) {
262 int i;
263 struct sk_buff *skb;
264
265 /* Check if the device queue is big
266 * enough for every fragment. If not, drop the
267 * whole packet.
268 */
269 for (i = 0; i < packet->txb->nr_frags; i++) {
270 skb = packet->txb->fragments[i];
271 if (unlikely(skb->len > queue->tx_devq_size)) {
272 dprintkl(KERN_ERR PFX "PIO TX device queue too small. "
273 "Dropping packet...\n");
274 free_txpacket(packet);
275 goto next_packet;
276 }
277 }
278 }
279 /* Now try to transmit the packet.
280 * This may not completely succeed.
281 */
282 err = pio_tx_packet(packet);
283 if (err)
284 break;
285next_packet:
286 continue;
287 }
288 spin_unlock_irqrestore(&queue->txlock, flags);
289}
290
291static void setup_txqueues(struct bcm43xx_pioqueue *queue)
292{
293 struct bcm43xx_pio_txpacket *packet;
294 int i;
295
296 for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) {
297 packet = queue->__tx_packets_cache + i;
298
299 packet->queue = queue;
300 INIT_LIST_HEAD(&packet->list);
301
302 list_add(&packet->list, &queue->txfree);
303 }
304}
305
306static
307struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,
308 u16 pio_mmio_base)
309{
310 struct bcm43xx_pioqueue *queue;
311 u32 value;
312 u16 qsize;
313
314 queue = kmalloc(sizeof(*queue), GFP_KERNEL);
315 if (!queue)
316 goto out;
317 memset(queue, 0, sizeof(*queue));
318
319 queue->bcm = bcm;
320 queue->mmio_base = pio_mmio_base;
321
322 INIT_LIST_HEAD(&queue->txfree);
323 INIT_LIST_HEAD(&queue->txqueue);
324 INIT_LIST_HEAD(&queue->txrunning);
325 spin_lock_init(&queue->txlock);
326 INIT_WORK(&queue->txwork, txwork_handler, queue);
327
328 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
329 value |= BCM43xx_SBF_XFER_REG_BYTESWAP;
330 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
331
332 qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
333 if (qsize <= BCM43xx_PIO_TXQADJUST) {
334 printk(KERN_ERR PFX "PIO tx queue too small (%u)\n", qsize);
335 goto err_freequeue;
336 }
337 qsize -= BCM43xx_PIO_TXQADJUST;
338 queue->tx_devq_size = qsize;
339
340 setup_txqueues(queue);
341
342out:
343 return queue;
344
345err_freequeue:
346 kfree(queue);
347 queue = NULL;
348 goto out;
349}
350
351static void cancel_transfers(struct bcm43xx_pioqueue *queue)
352{
353 struct bcm43xx_pio_txpacket *packet, *tmp_packet;
354
355 netif_tx_disable(queue->bcm->net_dev);
356 assert(queue->bcm->shutting_down);
357 cancel_delayed_work(&queue->txwork);
358 flush_workqueue(queue->bcm->workqueue);
359
360 list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
361 free_txpacket(packet);
362 list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
363 free_txpacket(packet);
364}
365
366static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue)
367{
368 if (!queue)
369 return;
370
371 cancel_transfers(queue);
372 kfree(queue);
373}
374
375void bcm43xx_pio_free(struct bcm43xx_private *bcm)
376{
377 bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue3);
378 bcm->current_core->pio->queue3 = NULL;
379 bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2);
380 bcm->current_core->pio->queue2 = NULL;
381 bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1);
382 bcm->current_core->pio->queue1 = NULL;
383 bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0);
384 bcm->current_core->pio->queue0 = NULL;
385}
386
387int bcm43xx_pio_init(struct bcm43xx_private *bcm)
388{
389 struct bcm43xx_pioqueue *queue;
390 int err = -ENOMEM;
391
392 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE);
393 if (!queue)
394 goto out;
395 bcm->current_core->pio->queue0 = queue;
396
397 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE);
398 if (!queue)
399 goto err_destroy0;
400 bcm->current_core->pio->queue1 = queue;
401
402 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE);
403 if (!queue)
404 goto err_destroy1;
405 bcm->current_core->pio->queue2 = queue;
406
407 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE);
408 if (!queue)
409 goto err_destroy2;
410 bcm->current_core->pio->queue3 = queue;
411
412 if (bcm->current_core->rev < 3)
413 bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND;
414
415 dprintk(KERN_INFO PFX "PIO initialized\n");
416 err = 0;
417out:
418 return err;
419
420err_destroy2:
421 bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2);
422 bcm->current_core->pio->queue2 = NULL;
423err_destroy1:
424 bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1);
425 bcm->current_core->pio->queue1 = NULL;
426err_destroy0:
427 bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0);
428 bcm->current_core->pio->queue0 = NULL;
429 goto out;
430}
431
432static inline
433int pio_transfer_txb(struct bcm43xx_pioqueue *queue,
434 struct ieee80211_txb *txb)
435{
436 struct bcm43xx_pio_txpacket *packet;
437 unsigned long flags;
438 u16 tmp;
439
440 spin_lock_irqsave(&queue->txlock, flags);
441 assert(!queue->tx_suspended);
442 assert(!list_empty(&queue->txfree));
443
444 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
445 if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) {
446 spin_unlock_irqrestore(&queue->txlock, flags);
447 return -EBUSY;
448 }
449
450 packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
451
452 packet->txb = txb;
453 list_move_tail(&packet->list, &queue->txqueue);
454 packet->xmitted_octets = 0;
455 packet->xmitted_frags = 0;
456
457 /* Suspend TX, if we are out of packets in the "free" queue. */
458 if (unlikely(list_empty(&queue->txfree))) {
459 netif_stop_queue(queue->bcm->net_dev);
460 queue->tx_suspended = 1;
461 }
462
463 spin_unlock_irqrestore(&queue->txlock, flags);
464 queue_work(queue->bcm->workqueue, &queue->txwork);
465
466 return 0;
467}
468
469int fastcall bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm,
470 struct ieee80211_txb *txb)
471{
472 return pio_transfer_txb(bcm->current_core->pio->queue1, txb);
473}
474
475void fastcall
476bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
477 struct bcm43xx_xmitstatus *status)
478{
479 struct bcm43xx_pioqueue *queue;
480 struct bcm43xx_pio_txpacket *packet;
481 unsigned long flags;
482
483 queue = parse_cookie(bcm, status->cookie, &packet);
484 assert(queue);
485 spin_lock_irqsave(&queue->txlock, flags);
486 free_txpacket(packet);
487 if (unlikely(queue->tx_suspended)) {
488 queue->tx_suspended = 0;
489 netif_wake_queue(queue->bcm->net_dev);
490 }
491
492 /* If there are packets on the txqueue,
493 * start the work handler again.
494 */
495 if (!list_empty(&queue->txqueue)) {
496 queue_work(queue->bcm->workqueue,
497 &queue->txwork);
498 }
499 spin_unlock_irqrestore(&queue->txlock, flags);
500}
501
502static void pio_rx_error(struct bcm43xx_pioqueue *queue,
503 const char *error)
504{
505 printk("PIO RX error: %s\n", error);
506 bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY);
507}
508
509void fastcall
510bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
511{
512 u16 preamble[21] = { 0 };
513 struct bcm43xx_rxhdr *rxhdr;
514 u16 tmp;
515 u16 len;
516 int i, err;
517 int preamble_readwords;
518 struct sk_buff *skb;
519
520 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
521 if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) {
522 dprintkl(KERN_ERR PFX "PIO RX: No data available\n");
523 return;
524 }
525 bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE);
526
527 for (i = 0; i < 10; i++) {
528 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
529 if (tmp & BCM43xx_PIO_RXCTL_READY)
530 goto data_ready;
531 udelay(10);
532 }
533 dprintkl(KERN_ERR PFX "PIO RX timed out\n");
534 return;
535data_ready:
536
537 len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
538 if (unlikely(len > 0x700)) {
539 pio_rx_error(queue, "len > 0x700");
540 return;
541 }
542 if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) {
543 pio_rx_error(queue, "len == 0");
544 return;
545 }
546 preamble[0] = cpu_to_le16(len);
547 if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE)
548 preamble_readwords = 14 / sizeof(u16);
549 else
550 preamble_readwords = 18 / sizeof(u16);
551 for (i = 0; i < preamble_readwords; i++) {
552 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
553 preamble[i + 1] = cpu_to_be16(tmp);
554 }
555 rxhdr = (struct bcm43xx_rxhdr *)preamble;
556 if (unlikely(rxhdr->flags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) {
557 pio_rx_error(queue, "invalid frame");
558 if (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE) {
559 for (i = 0; i < 15; i++)
560 bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); /* dummy read. */
561 }
562 return;
563 }
564//FIXME
565#if 0
566 if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) {
567 bcm43xx_rx_transmitstatus(queue->bcm,
568 (const struct bcm43xx_hwxmitstatus *)(preamble + 1));
569 return;
570 }
571#endif
572 skb = dev_alloc_skb(len);
573 if (unlikely(!skb)) {
574 pio_rx_error(queue, "out of memory");
575 return;
576 }
577 skb_put(skb, len);
578 for (i = 0; i < len - 1; i += 2) {
579 tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
580 *((u16 *)(skb->data + i)) = tmp;
581 }
582 if (len % 2) {
583 tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
584 skb->data[len - 1] = (tmp & 0x00FF);
585 skb->data[0] = (tmp & 0xFF00) >> 8;
586 }
587 err = bcm43xx_rx(queue->bcm, skb, rxhdr);
588 if (unlikely(err))
589 dev_kfree_skb_irq(skb);
590}
591
592/* vim: set ts=8 sw=8 sts=8: */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
new file mode 100644
index 000000000000..71b92ee34169
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -0,0 +1,88 @@
1#ifndef BCM43xx_PIO_H_
2#define BCM43xx_PIO_H_
3
4#include "bcm43xx.h"
5
6#include <linux/list.h>
7#include <linux/spinlock.h>
8#include <linux/workqueue.h>
9#include <linux/skbuff.h>
10
11
12#define BCM43xx_PIO_TXCTL 0x00
13#define BCM43xx_PIO_TXDATA 0x02
14#define BCM43xx_PIO_TXQBUFSIZE 0x04
15#define BCM43xx_PIO_RXCTL 0x08
16#define BCM43xx_PIO_RXDATA 0x0A
17
18#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0)
19#define BCM43xx_PIO_TXCTL_WRITELO (1 << 1)
20#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2)
21#define BCM43xx_PIO_TXCTL_INIT (1 << 3)
22#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7)
23
24#define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0)
25#define BCM43xx_PIO_RXCTL_READY (1 << 1)
26
27/* PIO constants */
28#define BCM43xx_PIO_MAXTXDEVQPACKETS 31
29#define BCM43xx_PIO_TXQADJUST 80
30
31/* PIO tuning knobs */
32#define BCM43xx_PIO_MAXTXPACKETS 256
33
34
35struct bcm43xx_pioqueue;
36struct bcm43xx_xmitstatus;
37
38struct bcm43xx_pio_txpacket {
39 struct bcm43xx_pioqueue *queue;
40 struct ieee80211_txb *txb;
41 struct list_head list;
42
43 u8 xmitted_frags;
44 u16 xmitted_octets;
45};
46
47#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->__tx_packets_cache))
48
49struct bcm43xx_pioqueue {
50 struct bcm43xx_private *bcm;
51 u16 mmio_base;
52
53 u8 tx_suspended:1;
54
55 /* Adjusted size of the device internal TX buffer. */
56 u16 tx_devq_size;
57 /* Used octets of the device internal TX buffer. */
58 u16 tx_devq_used;
59 /* Used packet slots in the device internal TX buffer. */
60 u8 tx_devq_packets;
61 /* Packets from the txfree list can
62 * be taken on incoming TX requests.
63 */
64 struct list_head txfree;
65 /* Packets on the txqueue are queued,
66 * but not completely written to the chip, yet.
67 */
68 struct list_head txqueue;
69 /* Packets on the txrunning queue are completely
70 * posted to the device. We are waiting for the txstatus.
71 */
72 struct list_head txrunning;
73 /* Locking of the TX queues and the accounting. */
74 spinlock_t txlock;
75 struct work_struct txwork;
76 struct bcm43xx_pio_txpacket __tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS];
77};
78
79int bcm43xx_pio_init(struct bcm43xx_private *bcm);
80void bcm43xx_pio_free(struct bcm43xx_private *bcm);
81
82int FASTCALL(bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm,
83 struct ieee80211_txb *txb));
84void FASTCALL(bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
85 struct bcm43xx_xmitstatus *status));
86
87void FASTCALL(bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue));
88#endif /* BCM43xx_PIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
new file mode 100644
index 000000000000..3c92b62807c5
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
@@ -0,0 +1,358 @@
1/*
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
33#include "bcm43xx.h"
34#include "bcm43xx_power.h"
35#include "bcm43xx_main.h"
36
37
38/* Get max/min slowclock frequency
39 * as described in http://bcm-specs.sipsolutions.net/PowerControl
40 */
41static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
42 int get_max)
43{
44 int limit = 0;
45 int divisor;
46 int selection;
47 int err;
48 u32 tmp;
49 struct bcm43xx_coreinfo *old_core;
50
51 if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
52 goto out;
53 old_core = bcm->current_core;
54 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
55 if (err)
56 goto out;
57
58 if (bcm->current_core->rev < 6) {
59 if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) ||
60 (bcm->bustype == BCM43xx_BUSTYPE_SB)) {
61 selection = 1;
62 divisor = 32;
63 } else {
64 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
65 if (err) {
66 printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n");
67 goto out_switchback;
68 }
69 if (tmp & 0x10) {
70 /* PCI */
71 selection = 2;
72 divisor = 64;
73 } else {
74 /* XTAL */
75 selection = 1;
76 divisor = 32;
77 }
78 }
79 } else if (bcm->current_core->rev < 10) {
80 selection = (tmp & 0x07);
81 if (selection) {
82 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
83 divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
84 } else
85 divisor = 1;
86 } else {
87 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
88 divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
89 selection = 1;
90 }
91
92 switch (selection) {
93 case 0:
94 /* LPO */
95 if (get_max)
96 limit = 43000;
97 else
98 limit = 25000;
99 break;
100 case 1:
101 /* XTAL */
102 if (get_max)
103 limit = 20200000;
104 else
105 limit = 19800000;
106 break;
107 case 2:
108 /* PCI */
109 if (get_max)
110 limit = 34000000;
111 else
112 limit = 25000000;
113 break;
114 default:
115 assert(0);
116 }
117 limit /= divisor;
118
119out_switchback:
120 err = bcm43xx_switch_core(bcm, old_core);
121 assert(err == 0);
122
123out:
124 return limit;
125}
126
127/* init power control
128 * as described in http://bcm-specs.sipsolutions.net/PowerControl
129 */
130int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
131{
132 int err, maxfreq;
133 struct bcm43xx_coreinfo *old_core;
134
135 if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
136 return 0;
137 old_core = bcm->current_core;
138 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
139 if (err == -ENODEV)
140 return 0;
141 if (err)
142 goto out;
143
144 maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
145 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
146 (maxfreq * 150 + 999999) / 1000000);
147 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
148 (maxfreq * 15 + 999999) / 1000000);
149
150 err = bcm43xx_switch_core(bcm, old_core);
151 assert(err == 0);
152
153out:
154 return err;
155}
156
157u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
158{
159 u16 delay = 0;
160 int err;
161 u32 pll_on_delay;
162 struct bcm43xx_coreinfo *old_core;
163 int minfreq;
164
165 if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
166 goto out;
167 if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
168 goto out;
169 old_core = bcm->current_core;
170 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
171 if (err == -ENODEV)
172 goto out;
173
174 minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
175 pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
176 delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
177
178 err = bcm43xx_switch_core(bcm, old_core);
179 assert(err == 0);
180
181out:
182 return delay;
183}
184
185/* set the powercontrol clock
186 * as described in http://bcm-specs.sipsolutions.net/PowerControl
187 */
188int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
189{
190 int err;
191 struct bcm43xx_coreinfo *old_core;
192 u32 tmp;
193
194 old_core = bcm->current_core;
195 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
196 if (err == -ENODEV)
197 return 0;
198 if (err)
199 goto out;
200
201 if (bcm->core_chipcommon.rev < 6) {
202 if (mode == BCM43xx_PCTL_CLK_FAST) {
203 err = bcm43xx_pctl_set_crystal(bcm, 1);
204 if (err)
205 goto out;
206 }
207 } else {
208 if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
209 (bcm->core_chipcommon.rev < 10)) {
210 switch (mode) {
211 case BCM43xx_PCTL_CLK_FAST:
212 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
213 tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
214 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
215 break;
216 case BCM43xx_PCTL_CLK_SLOW:
217 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
218 tmp |= BCM43xx_PCTL_FORCE_SLOW;
219 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
220 break;
221 case BCM43xx_PCTL_CLK_DYNAMIC:
222 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
223 tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
224 tmp |= BCM43xx_PCTL_FORCE_PLL;
225 tmp &= ~BCM43xx_PCTL_DYN_XTAL;
226 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
227 }
228 }
229 }
230
231 err = bcm43xx_switch_core(bcm, old_core);
232 assert(err == 0);
233
234out:
235 return err;
236}
237
238int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
239{
240 int err;
241 u32 in, out, outenable;
242
243 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
244 if (err)
245 goto err_pci;
246 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
247 if (err)
248 goto err_pci;
249 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
250 if (err)
251 goto err_pci;
252
253 outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
254
255 if (on) {
256 if (in & 0x40)
257 return 0;
258
259 out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
260
261 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
262 if (err)
263 goto err_pci;
264 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
265 if (err)
266 goto err_pci;
267 udelay(1000);
268
269 out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
270 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
271 if (err)
272 goto err_pci;
273 udelay(5000);
274 } else {
275 if (bcm->current_core->rev < 5)
276 return 0;
277 if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
278 return 0;
279
280/* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
281 * err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
282 * if (err)
283 * return err;
284 * if (((bcm->current_core->rev >= 3) &&
285 * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
286 * ((bcm->current_core->rev < 3) &&
287 * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
288 * return 0;
289 * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
290 * if (err)
291 * return err;
292 */
293
294 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
295 if (err)
296 goto out;
297 out &= ~BCM43xx_PCTL_XTAL_POWERUP;
298 out |= BCM43xx_PCTL_PLL_POWERDOWN;
299 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
300 if (err)
301 goto err_pci;
302 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
303 if (err)
304 goto err_pci;
305 }
306
307out:
308 return err;
309
310err_pci:
311 printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
312 err = -EBUSY;
313 goto out;
314}
315
316/* Set the PowerSavingControlBits.
317 * Bitvalues:
318 * 0 => unset the bit
319 * 1 => set the bit
320 * -1 => calculate the bit
321 */
322void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
323 int bit25, int bit26)
324{
325 int i;
326 u32 status;
327
328//FIXME: Force 25 to off and 26 to on for now:
329bit25 = 0;
330bit26 = 1;
331
332 if (bit25 == -1) {
333 //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
334 // and thus is not an AP and we are associated, set bit 25
335 }
336 if (bit26 == -1) {
337 //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
338 // or we are associated, or FIXME, or the latest PS-Poll packet sent was
339 // successful, set bit26
340 }
341 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
342 if (bit25)
343 status |= BCM43xx_SBF_PS1;
344 else
345 status &= ~BCM43xx_SBF_PS1;
346 if (bit26)
347 status |= BCM43xx_SBF_PS2;
348 else
349 status &= ~BCM43xx_SBF_PS2;
350 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
351 if (bit26 && bcm->current_core->rev >= 5) {
352 for (i = 0; i < 100; i++) {
353 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
354 break;
355 udelay(10);
356 }
357 }
358}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h
new file mode 100644
index 000000000000..5f63640810bd
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h
@@ -0,0 +1,47 @@
1/*
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#ifndef BCM43xx_POWER_H_
32#define BCM43xx_POWER_H_
33
34#include <linux/types.h>
35
36
37struct bcm43xx_private;
38
39int bcm43xx_pctl_init(struct bcm43xx_private *bcm);
40int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode);
41int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on);
42u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm);
43
44void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
45 int bit25, int bit26);
46
47#endif /* BCM43xx_POWER_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
new file mode 100644
index 000000000000..1e65658552b0
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -0,0 +1,1766 @@
1/*
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
33#include "bcm43xx.h"
34#include "bcm43xx_main.h"
35#include "bcm43xx_phy.h"
36#include "bcm43xx_radio.h"
37#include "bcm43xx_ilt.h"
38
39
40/* Table for bcm43xx_radio_calibrationvalue() */
41static const u16 rcc_table[16] = {
42 0x0002, 0x0003, 0x0001, 0x000F,
43 0x0006, 0x0007, 0x0005, 0x000F,
44 0x000A, 0x000B, 0x0009, 0x000F,
45 0x000E, 0x000F, 0x000D, 0x000F,
46};
47
48/* Reverse the bits of a 4bit value.
49 * Example: 1101 is flipped 1011
50 */
51static u16 flip_4bit(u16 value)
52{
53 u16 flipped = 0x0000;
54
55 assert((value & ~0x000F) == 0x0000);
56
57 flipped |= (value & 0x0001) << 3;
58 flipped |= (value & 0x0002) << 1;
59 flipped |= (value & 0x0004) >> 1;
60 flipped |= (value & 0x0008) >> 3;
61
62 return flipped;
63}
64
65/* Get the freq, as it has to be written to the device. */
66static inline
67u16 channel2freq_bg(u8 channel)
68{
69 /* Frequencies are given as frequencies_bg[index] + 2.4GHz
70 * Starting with channel 1
71 */
72 static const u16 frequencies_bg[14] = {
73 12, 17, 22, 27,
74 32, 37, 42, 47,
75 52, 57, 62, 67,
76 72, 84,
77 };
78
79 assert(channel >= 1 && channel <= 14);
80
81 return frequencies_bg[channel - 1];
82}
83
84/* Get the freq, as it has to be written to the device. */
85static inline
86u16 channel2freq_a(u8 channel)
87{
88 assert(channel <= 200);
89
90 return (5000 + 5 * channel);
91}
92
93void bcm43xx_radio_lock(struct bcm43xx_private *bcm)
94{
95 u32 status;
96
97 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
98 status |= BCM43xx_SBF_RADIOREG_LOCK;
99 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
100 udelay(10);
101}
102
103void bcm43xx_radio_unlock(struct bcm43xx_private *bcm)
104{
105 u32 status;
106
107 bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */
108 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
109 status &= ~BCM43xx_SBF_RADIOREG_LOCK;
110 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
111}
112
113u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset)
114{
115 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
116 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
117
118 switch (phy->type) {
119 case BCM43xx_PHYTYPE_A:
120 offset |= 0x0040;
121 break;
122 case BCM43xx_PHYTYPE_B:
123 if (radio->version == 0x2053) {
124 if (offset < 0x70)
125 offset += 0x80;
126 else if (offset < 0x80)
127 offset += 0x70;
128 } else if (radio->version == 0x2050) {
129 offset |= 0x80;
130 } else
131 assert(0);
132 break;
133 case BCM43xx_PHYTYPE_G:
134 offset |= 0x80;
135 break;
136 }
137
138 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
139 return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
140}
141
142void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val)
143{
144 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
145 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val);
146}
147
148static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm,
149 s16 first, s16 second, s16 third)
150{
151 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
152 u16 i;
153 u16 start = 0x08, end = 0x18;
154 u16 offset = 0x0400;
155 u16 tmp;
156
157 if (phy->rev <= 1) {
158 offset = 0x5000;
159 start = 0x10;
160 end = 0x20;
161 }
162
163 for (i = 0; i < 4; i++)
164 bcm43xx_ilt_write16(bcm, offset + i, first);
165
166 for (i = start; i < end; i++)
167 bcm43xx_ilt_write16(bcm, offset + i, second);
168
169 if (third != -1) {
170 tmp = ((u16)third << 14) | ((u16)third << 6);
171 bcm43xx_phy_write(bcm, 0x04A0,
172 (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp);
173 bcm43xx_phy_write(bcm, 0x04A1,
174 (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp);
175 bcm43xx_phy_write(bcm, 0x04A2,
176 (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp);
177 }
178 bcm43xx_dummy_transmission(bcm);
179}
180
181static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm)
182{
183 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
184 u16 i, tmp;
185 u16 offset = 0x0400;
186 u16 start = 0x0008, end = 0x0018;
187
188 if (phy->rev <= 1) {
189 offset = 0x5000;
190 start = 0x0010;
191 end = 0x0020;
192 }
193
194 for (i = 0; i < 4; i++) {
195 tmp = (i & 0xFFFC);
196 tmp |= (i & 0x0001) << 1;
197 tmp |= (i & 0x0002) >> 1;
198
199 bcm43xx_ilt_write16(bcm, offset + i, tmp);
200 }
201
202 for (i = start; i < end; i++)
203 bcm43xx_ilt_write16(bcm, offset + i, i - start);
204
205 bcm43xx_phy_write(bcm, 0x04A0,
206 (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040);
207 bcm43xx_phy_write(bcm, 0x04A1,
208 (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040);
209 bcm43xx_phy_write(bcm, 0x04A2,
210 (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000);
211 bcm43xx_dummy_transmission(bcm);
212}
213
214/* Synthetic PU workaround */
215static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel)
216{
217 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
218
219 if (radio->version != 0x2050 || radio->revision >= 6) {
220 /* We do not need the workaround. */
221 return;
222 }
223
224 if (channel <= 10) {
225 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
226 channel2freq_bg(channel + 4));
227 } else {
228 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
229 channel2freq_bg(1));
230 }
231 udelay(100);
232 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
233 channel2freq_bg(channel));
234}
235
236u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel)
237{
238 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
239 u8 ret = 0;
240 u16 saved, rssi, temp;
241 int i, j = 0;
242
243 saved = bcm43xx_phy_read(bcm, 0x0403);
244 bcm43xx_radio_selectchannel(bcm, channel, 0);
245 bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5);
246 if (radio->aci_hw_rssi)
247 rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F;
248 else
249 rssi = saved & 0x3F;
250 /* clamp temp to signed 5bit */
251 if (rssi > 32)
252 rssi -= 64;
253 for (i = 0;i < 100; i++) {
254 temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F;
255 if (temp > 32)
256 temp -= 64;
257 if (temp < rssi)
258 j++;
259 if (j >= 20)
260 ret = 1;
261 }
262 bcm43xx_phy_write(bcm, 0x0403, saved);
263
264 return ret;
265}
266
267u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm)
268{
269 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
270 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
271 u8 ret[13];
272 unsigned int channel = radio->channel;
273 unsigned int i, j, start, end;
274 unsigned long phylock_flags;
275
276 if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0)))
277 return 0;
278
279 bcm43xx_phy_lock(bcm, phylock_flags);
280 bcm43xx_radio_lock(bcm);
281 bcm43xx_phy_write(bcm, 0x0802,
282 bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
283 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
284 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
285 bcm43xx_set_all_gains(bcm, 3, 8, 1);
286
287 start = (channel - 5 > 0) ? channel - 5 : 1;
288 end = (channel + 5 < 14) ? channel + 5 : 13;
289
290 for (i = start; i <= end; i++) {
291 if (abs(channel - i) > 2)
292 ret[i-1] = bcm43xx_radio_aci_detect(bcm, i);
293 }
294 bcm43xx_radio_selectchannel(bcm, channel, 0);
295 bcm43xx_phy_write(bcm, 0x0802,
296 (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003);
297 bcm43xx_phy_write(bcm, 0x0403,
298 bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8);
299 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
300 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
301 bcm43xx_set_original_gains(bcm);
302 for (i = 0; i < 13; i++) {
303 if (!ret[i])
304 continue;
305 end = (i + 5 < 13) ? i + 5 : 13;
306 for (j = i; j < end; j++)
307 ret[j] = 1;
308 }
309 bcm43xx_radio_unlock(bcm);
310 bcm43xx_phy_unlock(bcm, phylock_flags);
311
312 return ret[channel - 1];
313}
314
315/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
316void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val)
317{
318 bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
319 bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val);
320}
321
322/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
323s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset)
324{
325 u16 val;
326
327 bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
328 val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA);
329
330 return (s16)val;
331}
332
333/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
334void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val)
335{
336 u16 i;
337 s16 tmp;
338
339 for (i = 0; i < 64; i++) {
340 tmp = bcm43xx_nrssi_hw_read(bcm, i);
341 tmp -= val;
342 tmp = limit_value(tmp, -32, 31);
343 bcm43xx_nrssi_hw_write(bcm, i, tmp);
344 }
345}
346
347/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
348void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm)
349{
350 s16 i, delta;
351 s32 tmp;
352
353 delta = 0x1F - bcm->current_core->radio->nrssi[0];
354 for (i = 0; i < 64; i++) {
355 tmp = (i - delta) * bcm->current_core->radio->nrssislope;
356 tmp /= 0x10000;
357 tmp += 0x3A;
358 tmp = limit_value(tmp, 0, 0x3F);
359 bcm->current_core->radio->nrssi_lt[i] = tmp;
360 }
361}
362
363static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
364{
365 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
366 u16 backup[20] = { 0 };
367 s16 v47F;
368 u16 i;
369 u16 saved = 0xFFFF;
370
371 backup[0] = bcm43xx_phy_read(bcm, 0x0001);
372 backup[1] = bcm43xx_phy_read(bcm, 0x0811);
373 backup[2] = bcm43xx_phy_read(bcm, 0x0812);
374 backup[3] = bcm43xx_phy_read(bcm, 0x0814);
375 backup[4] = bcm43xx_phy_read(bcm, 0x0815);
376 backup[5] = bcm43xx_phy_read(bcm, 0x005A);
377 backup[6] = bcm43xx_phy_read(bcm, 0x0059);
378 backup[7] = bcm43xx_phy_read(bcm, 0x0058);
379 backup[8] = bcm43xx_phy_read(bcm, 0x000A);
380 backup[9] = bcm43xx_phy_read(bcm, 0x0003);
381 backup[10] = bcm43xx_radio_read16(bcm, 0x007A);
382 backup[11] = bcm43xx_radio_read16(bcm, 0x0043);
383
384 bcm43xx_phy_write(bcm, 0x0429,
385 bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF);
386 bcm43xx_phy_write(bcm, 0x0001,
387 (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000);
388 bcm43xx_phy_write(bcm, 0x0811,
389 bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
390 bcm43xx_phy_write(bcm, 0x0812,
391 (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004);
392 bcm43xx_phy_write(bcm, 0x0802,
393 bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2));
394 if (phy->rev >= 6) {
395 backup[12] = bcm43xx_phy_read(bcm, 0x002E);
396 backup[13] = bcm43xx_phy_read(bcm, 0x002F);
397 backup[14] = bcm43xx_phy_read(bcm, 0x080F);
398 backup[15] = bcm43xx_phy_read(bcm, 0x0810);
399 backup[16] = bcm43xx_phy_read(bcm, 0x0801);
400 backup[17] = bcm43xx_phy_read(bcm, 0x0060);
401 backup[18] = bcm43xx_phy_read(bcm, 0x0014);
402 backup[19] = bcm43xx_phy_read(bcm, 0x0478);
403
404 bcm43xx_phy_write(bcm, 0x002E, 0);
405 bcm43xx_phy_write(bcm, 0x002F, 0);
406 bcm43xx_phy_write(bcm, 0x080F, 0);
407 bcm43xx_phy_write(bcm, 0x0810, 0);
408 bcm43xx_phy_write(bcm, 0x0478,
409 bcm43xx_phy_read(bcm, 0x0478) | 0x0100);
410 bcm43xx_phy_write(bcm, 0x0801,
411 bcm43xx_phy_read(bcm, 0x0801) | 0x0040);
412 bcm43xx_phy_write(bcm, 0x0060,
413 bcm43xx_phy_read(bcm, 0x0060) | 0x0040);
414 bcm43xx_phy_write(bcm, 0x0014,
415 bcm43xx_phy_read(bcm, 0x0014) | 0x0200);
416 }
417 bcm43xx_radio_write16(bcm, 0x007A,
418 bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
419 bcm43xx_radio_write16(bcm, 0x007A,
420 bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
421 udelay(30);
422
423 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
424 if (v47F >= 0x20)
425 v47F -= 0x40;
426 if (v47F == 31) {
427 for (i = 7; i >= 4; i--) {
428 bcm43xx_radio_write16(bcm, 0x007B, i);
429 udelay(20);
430 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
431 if (v47F >= 0x20)
432 v47F -= 0x40;
433 if (v47F < 31 && saved == 0xFFFF)
434 saved = i;
435 }
436 if (saved == 0xFFFF)
437 saved = 4;
438 } else {
439 bcm43xx_radio_write16(bcm, 0x007A,
440 bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
441 bcm43xx_phy_write(bcm, 0x0814,
442 bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
443 bcm43xx_phy_write(bcm, 0x0815,
444 bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
445 bcm43xx_phy_write(bcm, 0x0811,
446 bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
447 bcm43xx_phy_write(bcm, 0x0812,
448 bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
449 bcm43xx_phy_write(bcm, 0x0811,
450 bcm43xx_phy_read(bcm, 0x0811) | 0x0030);
451 bcm43xx_phy_write(bcm, 0x0812,
452 bcm43xx_phy_read(bcm, 0x0812) | 0x0030);
453 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
454 bcm43xx_phy_write(bcm, 0x0059, 0x0810);
455 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
456 if (phy->rev == 0) {
457 bcm43xx_phy_write(bcm, 0x0003, 0x0122);
458 } else {
459 bcm43xx_phy_write(bcm, 0x000A,
460 bcm43xx_phy_read(bcm, 0x000A)
461 | 0x2000);
462 }
463 bcm43xx_phy_write(bcm, 0x0814,
464 bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
465 bcm43xx_phy_write(bcm, 0x0815,
466 bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
467 bcm43xx_phy_write(bcm, 0x0003,
468 (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F)
469 | 0x0040);
470 bcm43xx_phy_write(bcm, 0x007A,
471 bcm43xx_phy_read(bcm, 0x007A) | 0x000F);
472 bcm43xx_set_all_gains(bcm, 3, 0, 1);
473 bcm43xx_radio_write16(bcm, 0x0043,
474 (bcm43xx_radio_read16(bcm, 0x0043)
475 & 0x00F0) | 0x000F);
476 udelay(30);
477 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
478 if (v47F >= 0x20)
479 v47F -= 0x40;
480 if (v47F == -32) {
481 for (i = 0; i < 4; i++) {
482 bcm43xx_radio_write16(bcm, 0x007B, i);
483 udelay(20);
484 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
485 if (v47F >= 0x20)
486 v47F -= 0x40;
487 if (v47F > -31 && saved == 0xFFFF)
488 saved = i;
489 }
490 if (saved == 0xFFFF)
491 saved = 3;
492 } else
493 saved = 0;
494 }
495 bcm43xx_radio_write16(bcm, 0x007B, saved);
496
497 if (phy->rev >= 6) {
498 bcm43xx_phy_write(bcm, 0x002E, backup[12]);
499 bcm43xx_phy_write(bcm, 0x002F, backup[13]);
500 bcm43xx_phy_write(bcm, 0x080F, backup[14]);
501 bcm43xx_phy_write(bcm, 0x0810, backup[15]);
502 }
503 bcm43xx_phy_write(bcm, 0x0814, backup[3]);
504 bcm43xx_phy_write(bcm, 0x0815, backup[4]);
505 bcm43xx_phy_write(bcm, 0x005A, backup[5]);
506 bcm43xx_phy_write(bcm, 0x0059, backup[6]);
507 bcm43xx_phy_write(bcm, 0x0058, backup[7]);
508 bcm43xx_phy_write(bcm, 0x000A, backup[8]);
509 bcm43xx_phy_write(bcm, 0x0003, backup[9]);
510 bcm43xx_radio_write16(bcm, 0x0043, backup[11]);
511 bcm43xx_radio_write16(bcm, 0x007A, backup[10]);
512 bcm43xx_phy_write(bcm, 0x0802,
513 bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2);
514 bcm43xx_phy_write(bcm, 0x0429,
515 bcm43xx_phy_read(bcm, 0x0429) | 0x8000);
516 bcm43xx_set_original_gains(bcm);
517 if (phy->rev >= 6) {
518 bcm43xx_phy_write(bcm, 0x0801, backup[16]);
519 bcm43xx_phy_write(bcm, 0x0060, backup[17]);
520 bcm43xx_phy_write(bcm, 0x0014, backup[18]);
521 bcm43xx_phy_write(bcm, 0x0478, backup[19]);
522 }
523 bcm43xx_phy_write(bcm, 0x0001, backup[0]);
524 bcm43xx_phy_write(bcm, 0x0812, backup[2]);
525 bcm43xx_phy_write(bcm, 0x0811, backup[1]);
526}
527
528void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
529{
530 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
531 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
532 u16 backup[18] = { 0 };
533 u16 tmp;
534 s16 nrssi0, nrssi1;
535
536 switch (phy->type) {
537 case BCM43xx_PHYTYPE_B:
538 backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
539 backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
540 backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
541 backup[3] = bcm43xx_phy_read(bcm, 0x0030);
542 backup[4] = bcm43xx_phy_read(bcm, 0x0026);
543 backup[5] = bcm43xx_phy_read(bcm, 0x0015);
544 backup[6] = bcm43xx_phy_read(bcm, 0x002A);
545 backup[7] = bcm43xx_phy_read(bcm, 0x0020);
546 backup[8] = bcm43xx_phy_read(bcm, 0x005A);
547 backup[9] = bcm43xx_phy_read(bcm, 0x0059);
548 backup[10] = bcm43xx_phy_read(bcm, 0x0058);
549 backup[11] = bcm43xx_read16(bcm, 0x03E2);
550 backup[12] = bcm43xx_read16(bcm, 0x03E6);
551 backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
552
553 tmp = bcm43xx_radio_read16(bcm, 0x007A);
554 tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
555 bcm43xx_radio_write16(bcm, 0x007A, tmp);
556 bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
557 bcm43xx_write16(bcm, 0x03EC, 0x7F7F);
558 bcm43xx_phy_write(bcm, 0x0026, 0x0000);
559 bcm43xx_phy_write(bcm, 0x0015,
560 bcm43xx_phy_read(bcm, 0x0015) | 0x0020);
561 bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
562 bcm43xx_radio_write16(bcm, 0x007A,
563 bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
564
565 nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027);
566 bcm43xx_radio_write16(bcm, 0x007A,
567 bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
568 if (phy->rev >= 2) {
569 bcm43xx_write16(bcm, 0x03E6, 0x0040);
570 } else if (phy->rev == 0) {
571 bcm43xx_write16(bcm, 0x03E6, 0x0122);
572 } else {
573 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
574 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000);
575 }
576 bcm43xx_phy_write(bcm, 0x0020, 0x3F3F);
577 bcm43xx_phy_write(bcm, 0x0015, 0xF330);
578 bcm43xx_radio_write16(bcm, 0x005A, 0x0060);
579 bcm43xx_radio_write16(bcm, 0x0043,
580 bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0);
581 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
582 bcm43xx_phy_write(bcm, 0x0059, 0x0810);
583 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
584 udelay(20);
585
586 nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027);
587 bcm43xx_phy_write(bcm, 0x0030, backup[3]);
588 bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
589 bcm43xx_write16(bcm, 0x03E2, backup[11]);
590 bcm43xx_phy_write(bcm, 0x0026, backup[4]);
591 bcm43xx_phy_write(bcm, 0x0015, backup[5]);
592 bcm43xx_phy_write(bcm, 0x002A, backup[6]);
593 bcm43xx_synth_pu_workaround(bcm, radio->channel);
594 if (phy->rev != 0)
595 bcm43xx_write16(bcm, 0x03F4, backup[13]);
596
597 bcm43xx_phy_write(bcm, 0x0020, backup[7]);
598 bcm43xx_phy_write(bcm, 0x005A, backup[8]);
599 bcm43xx_phy_write(bcm, 0x0059, backup[9]);
600 bcm43xx_phy_write(bcm, 0x0058, backup[10]);
601 bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
602 bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
603
604 if (nrssi0 == nrssi1)
605 radio->nrssislope = 0x00010000;
606 else
607 radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
608
609 if (nrssi0 <= -4) {
610 radio->nrssi[0] = nrssi0;
611 radio->nrssi[1] = nrssi1;
612 }
613 break;
614 case BCM43xx_PHYTYPE_G:
615//FIXME: Something is broken here. This is called when enabling WLAN interfmode.
616// If this is done at runtime, I get an XMIT ERROR and transmission is
617// broken. I guess some important register is overwritten by accident.
618// The XMIT ERROR comes from the dummy_transmissions in set_gains.
619 if (radio->revision >= 9)
620 return;
621 if (radio->revision == 8)
622 bcm43xx_calc_nrssi_offset(bcm);
623
624 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
625 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
626 bcm43xx_phy_write(bcm, 0x0802,
627 bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
628 backup[7] = bcm43xx_read16(bcm, 0x03E2);
629 bcm43xx_write16(bcm, 0x03E2,
630 bcm43xx_read16(bcm, 0x03E2) | 0x8000);
631 backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
632 backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
633 backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
634 backup[3] = bcm43xx_phy_read(bcm, 0x0015);
635 backup[4] = bcm43xx_phy_read(bcm, 0x005A);
636 backup[5] = bcm43xx_phy_read(bcm, 0x0059);
637 backup[6] = bcm43xx_phy_read(bcm, 0x0058);
638 backup[8] = bcm43xx_read16(bcm, 0x03E6);
639 backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
640 if (phy->rev >= 3) {
641 backup[10] = bcm43xx_phy_read(bcm, 0x002E);
642 backup[11] = bcm43xx_phy_read(bcm, 0x002F);
643 backup[12] = bcm43xx_phy_read(bcm, 0x080F);
644 backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL);
645 backup[14] = bcm43xx_phy_read(bcm, 0x0801);
646 backup[15] = bcm43xx_phy_read(bcm, 0x0060);
647 backup[16] = bcm43xx_phy_read(bcm, 0x0014);
648 backup[17] = bcm43xx_phy_read(bcm, 0x0478);
649 bcm43xx_phy_write(bcm, 0x002E, 0);
650 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0);
651 switch (phy->rev) {
652 case 4: case 6: case 7:
653 bcm43xx_phy_write(bcm, 0x0478,
654 bcm43xx_phy_read(bcm, 0x0478)
655 | 0x0100);
656 bcm43xx_phy_write(bcm, 0x0801,
657 bcm43xx_phy_read(bcm, 0x0801)
658 | 0x0040);
659 break;
660 case 3: case 5:
661 bcm43xx_phy_write(bcm, 0x0801,
662 bcm43xx_phy_read(bcm, 0x0801)
663 & 0xFFBF);
664 break;
665 }
666 bcm43xx_phy_write(bcm, 0x0060,
667 bcm43xx_phy_read(bcm, 0x0060)
668 | 0x0040);
669 bcm43xx_phy_write(bcm, 0x0014,
670 bcm43xx_phy_read(bcm, 0x0014)
671 | 0x0200);
672 }
673 bcm43xx_radio_write16(bcm, 0x007A,
674 bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
675 bcm43xx_set_all_gains(bcm, 0, 8, 0);
676 bcm43xx_radio_write16(bcm, 0x007A,
677 bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7);
678 if (phy->rev >= 2) {
679 bcm43xx_phy_write(bcm, 0x0811,
680 (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030);
681 bcm43xx_phy_write(bcm, 0x0812,
682 (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010);
683 }
684 bcm43xx_radio_write16(bcm, 0x007A,
685 bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
686 udelay(20);
687
688 nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
689 if (nrssi0 >= 0x0020)
690 nrssi0 -= 0x0040;
691
692 bcm43xx_radio_write16(bcm, 0x007A,
693 bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
694 if (phy->rev >= 2) {
695 bcm43xx_phy_write(bcm, 0x0003,
696 (bcm43xx_phy_read(bcm, 0x0003)
697 & 0xFF9F) | 0x0040);
698 }
699
700 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
701 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
702 | 0x2000);
703 bcm43xx_radio_write16(bcm, 0x007A,
704 bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
705 bcm43xx_phy_write(bcm, 0x0015, 0xF330);
706 if (phy->rev >= 2) {
707 bcm43xx_phy_write(bcm, 0x0812,
708 (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020);
709 bcm43xx_phy_write(bcm, 0x0811,
710 (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020);
711 }
712
713 bcm43xx_set_all_gains(bcm, 3, 0, 1);
714 if (radio->revision == 8) {
715 bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
716 } else {
717 tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F;
718 bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060);
719 tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0;
720 bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009);
721 }
722 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
723 bcm43xx_phy_write(bcm, 0x0059, 0x0810);
724 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
725 udelay(20);
726 nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
727 if (nrssi1 >= 0x0020)
728 nrssi1 -= 0x0040;
729 if (nrssi0 == nrssi1)
730 radio->nrssislope = 0x00010000;
731 else
732 radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
733 if (nrssi0 >= -4) {
734 radio->nrssi[0] = nrssi1;
735 radio->nrssi[1] = nrssi0;
736 }
737 if (phy->rev >= 3) {
738 bcm43xx_phy_write(bcm, 0x002E, backup[10]);
739 bcm43xx_phy_write(bcm, 0x002F, backup[11]);
740 bcm43xx_phy_write(bcm, 0x080F, backup[12]);
741 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]);
742 }
743 if (phy->rev >= 2) {
744 bcm43xx_phy_write(bcm, 0x0812,
745 bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF);
746 bcm43xx_phy_write(bcm, 0x0811,
747 bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF);
748 }
749
750 bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
751 bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
752 bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
753 bcm43xx_write16(bcm, 0x03E2, backup[7]);
754 bcm43xx_write16(bcm, 0x03E6, backup[8]);
755 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]);
756 bcm43xx_phy_write(bcm, 0x0015, backup[3]);
757 bcm43xx_phy_write(bcm, 0x005A, backup[4]);
758 bcm43xx_phy_write(bcm, 0x0059, backup[5]);
759 bcm43xx_phy_write(bcm, 0x0058, backup[6]);
760 bcm43xx_synth_pu_workaround(bcm, radio->channel);
761 bcm43xx_phy_write(bcm, 0x0802,
762 bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002));
763 bcm43xx_set_original_gains(bcm);
764 bcm43xx_phy_write(bcm, 0x0802,
765 bcm43xx_phy_read(bcm, 0x0802) | 0x8000);
766 if (phy->rev >= 3) {
767 bcm43xx_phy_write(bcm, 0x0801, backup[14]);
768 bcm43xx_phy_write(bcm, 0x0060, backup[15]);
769 bcm43xx_phy_write(bcm, 0x0014, backup[16]);
770 bcm43xx_phy_write(bcm, 0x0478, backup[17]);
771 }
772 bcm43xx_nrssi_mem_update(bcm);
773 bcm43xx_calc_nrssi_threshold(bcm);
774 break;
775 default:
776 assert(0);
777 }
778}
779
780void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm)
781{
782 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
783 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
784 s16 threshold;
785 s32 a, b;
786 int tmp;
787 s16 tmp16;
788 u16 tmp_u16;
789
790 switch (phy->type) {
791 case BCM43xx_PHYTYPE_B: {
792 int radiotype = 0;
793
794 if (phy->rev < 2)
795 return;
796 if (radio->version != 0x2050)
797 return;
798 if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI))
799 return;
800
801 tmp = radio->revision;
802 if ((radio->manufact == 0x175 && tmp == 5) ||
803 (radio->manufact == 0x17F && (tmp == 3 || tmp == 4)))
804 radiotype = 1;
805
806 if (radiotype == 1) {
807 threshold = bcm->current_core->radio->nrssi[1] - 5;
808 } else {
809 threshold = 40 * radio->nrssi[0];
810 threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]);
811 threshold += 20;
812 threshold /= 10;
813 }
814 threshold = limit_value(threshold, 0, 0x3E);
815 bcm43xx_phy_read(bcm, 0x0020); /* dummy read */
816 bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C);
817
818 if (radiotype == 1) {
819 bcm43xx_phy_write(bcm, 0x0087, 0x0E0D);
820 bcm43xx_phy_write(bcm, 0x0086, 0x0C0B);
821 bcm43xx_phy_write(bcm, 0x0085, 0x0A09);
822 bcm43xx_phy_write(bcm, 0x0084, 0x0808);
823 bcm43xx_phy_write(bcm, 0x0083, 0x0808);
824 bcm43xx_phy_write(bcm, 0x0082, 0x0604);
825 bcm43xx_phy_write(bcm, 0x0081, 0x0302);
826 bcm43xx_phy_write(bcm, 0x0080, 0x0100);
827 }
828 break;
829 }
830 case BCM43xx_PHYTYPE_G:
831 if (!phy->connected ||
832 !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
833 tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20);
834 if (tmp16 >= 0x20)
835 tmp16 -= 0x40;
836 if (tmp16 < 3) {
837 bcm43xx_phy_write(bcm, 0x048A,
838 (bcm43xx_phy_read(bcm, 0x048A)
839 & 0xF000) | 0x09EB);
840 } else {
841 bcm43xx_phy_write(bcm, 0x048A,
842 (bcm43xx_phy_read(bcm, 0x048A)
843 & 0xF000) | 0x0AED);
844 }
845 } else {
846 tmp = radio->interfmode;
847 if (tmp == BCM43xx_RADIO_INTERFMODE_NONWLAN) {
848 a = -13;
849 b = -17;
850 } else if (tmp == BCM43xx_RADIO_INTERFMODE_NONE &&
851 !radio->aci_enable) {
852 a = -13;
853 b = -10;
854 } else {
855 a = -8;
856 b = -9;
857 }
858 a += 0x1B;
859 a *= radio->nrssi[1] - radio->nrssi[0];
860 a += radio->nrssi[0] * 0x40;
861 a /= 64;
862 b += 0x1B;
863 b *= radio->nrssi[1] - radio->nrssi[0];
864 b += radio->nrssi[0] * 0x40;
865 b /= 64;
866
867 a = limit_value(a, -31, 31);
868 b = limit_value(b, -31, 31);
869
870 tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000;
871 tmp_u16 |= ((u32)a & 0x003F);
872 tmp_u16 |= (((u32)b & 0x003F) << 6);
873 bcm43xx_phy_write(bcm, 0x048A, tmp_u16);
874 }
875 break;
876 default:
877 assert(0);
878 }
879}
880
881/* Helper macros to save on and restore values from the radio->interfstack */
882#ifdef stack_save
883# undef stack_save
884#endif
885#ifdef stack_restore
886# undef stack_restore
887#endif
888#define stack_save(value) \
889 do { \
890 assert(i < ARRAY_SIZE(radio->interfstack)); \
891 stack[i++] = (value); \
892 } while (0)
893
894#define stack_restore() \
895 ({ \
896 assert(i < ARRAY_SIZE(radio->interfstack)); \
897 stack[i++]; \
898 })
899
900static void
901bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm,
902 int mode)
903{
904 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
905 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
906 int i = 0;
907 u16 *stack = radio->interfstack;
908 u16 tmp, flipped;
909
910 switch (mode) {
911 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
912 if (phy->rev != 1) {
913 bcm43xx_phy_write(bcm, 0x042B,
914 bcm43xx_phy_read(bcm, 0x042B) & 0x0800);
915 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
916 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000);
917 break;
918 }
919 tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E);
920 flipped = flip_4bit(tmp);
921 if ((flipped >> 1) >= 4)
922 tmp = flipped - 3;
923 tmp = flip_4bit(tmp);
924 bcm43xx_radio_write16(bcm, 0x0078, tmp << 1);
925
926 bcm43xx_calc_nrssi_threshold(bcm);
927
928 if (bcm->current_core->rev < 5) {
929 stack_save(bcm43xx_phy_read(bcm, 0x0406));
930 bcm43xx_phy_write(bcm, 0x0406, 0x7E28);
931 } else {
932 stack_save(bcm43xx_phy_read(bcm, 0x04C0));
933 stack_save(bcm43xx_phy_read(bcm, 0x04C1));
934 bcm43xx_phy_write(bcm, 0x04C0, 0x3E04);
935 bcm43xx_phy_write(bcm, 0x04C1, 0x0640);
936 }
937
938 bcm43xx_phy_write(bcm, 0x042B,
939 bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
940 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
941 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000);
942
943 stack_save(bcm43xx_phy_read(bcm, 0x04A0));
944 bcm43xx_phy_write(bcm, 0x04A0,
945 (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008);
946 stack_save(bcm43xx_phy_read(bcm, 0x04A1));
947 bcm43xx_phy_write(bcm, 0x04A1,
948 (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605);
949 stack_save(bcm43xx_phy_read(bcm, 0x04A2));
950 bcm43xx_phy_write(bcm, 0x04A2,
951 (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204);
952 stack_save(bcm43xx_phy_read(bcm, 0x04A8));
953 bcm43xx_phy_write(bcm, 0x04A8,
954 (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0403);
955 stack_save(bcm43xx_phy_read(bcm, 0x04AB));
956 bcm43xx_phy_write(bcm, 0x04AB,
957 (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0504);
958
959 stack_save(bcm43xx_phy_read(bcm, 0x04A7));
960 bcm43xx_phy_write(bcm, 0x04A7, 0x0002);
961 stack_save(bcm43xx_phy_read(bcm, 0x04A3));
962 bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
963 stack_save(bcm43xx_phy_read(bcm, 0x04A9));
964 bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
965 stack_save(bcm43xx_phy_read(bcm, 0x0493));
966 bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
967 stack_save(bcm43xx_phy_read(bcm, 0x04AA));
968 bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
969 stack_save(bcm43xx_phy_read(bcm, 0x04AC));
970 bcm43xx_phy_write(bcm, 0x04AC, 0x32F5);
971 break;
972 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
973 if (bcm43xx_phy_read(bcm, 0x0033) == 0x0800)
974 break;
975
976 radio->aci_enable = 1;
977
978 stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD));
979 stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS));
980 if (bcm->current_core->rev < 5) {
981 stack_save(bcm43xx_phy_read(bcm, 0x0406));
982 } else {
983 stack_save(bcm43xx_phy_read(bcm, 0x04C0));
984 stack_save(bcm43xx_phy_read(bcm, 0x04C1));
985 }
986 stack_save(bcm43xx_phy_read(bcm, 0x0033));
987 stack_save(bcm43xx_phy_read(bcm, 0x04A7));
988 stack_save(bcm43xx_phy_read(bcm, 0x04A3));
989 stack_save(bcm43xx_phy_read(bcm, 0x04A9));
990 stack_save(bcm43xx_phy_read(bcm, 0x04AA));
991 stack_save(bcm43xx_phy_read(bcm, 0x04AC));
992 stack_save(bcm43xx_phy_read(bcm, 0x0493));
993 stack_save(bcm43xx_phy_read(bcm, 0x04A1));
994 stack_save(bcm43xx_phy_read(bcm, 0x04A0));
995 stack_save(bcm43xx_phy_read(bcm, 0x04A2));
996 stack_save(bcm43xx_phy_read(bcm, 0x048A));
997 stack_save(bcm43xx_phy_read(bcm, 0x04A8));
998 stack_save(bcm43xx_phy_read(bcm, 0x04AB));
999
1000 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
1001 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & 0xEFFF);
1002 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1003 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xEFFF) | 0x0002);
1004
1005 bcm43xx_phy_write(bcm, 0x04A7, 0x0800);
1006 bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
1007 bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
1008 bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
1009 bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
1010 bcm43xx_phy_write(bcm, 0x04AC, 0x32F5);
1011
1012 bcm43xx_phy_write(bcm, 0x04A0,
1013 (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFC0) | 0x001A);
1014 if (bcm->current_core->rev < 5) {
1015 bcm43xx_phy_write(bcm, 0x0406, 0x280D);
1016 } else {
1017 bcm43xx_phy_write(bcm, 0x04C0, 0x0640);
1018 bcm43xx_phy_write(bcm, 0x04C1, 0x00A9);
1019 }
1020
1021 bcm43xx_phy_write(bcm, 0x04A1,
1022 (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0FF) | 0x1800);
1023 bcm43xx_phy_write(bcm, 0x04A1,
1024 (bcm43xx_phy_read(bcm, 0x04A1) & 0xFFC0) | 0x0016);
1025 bcm43xx_phy_write(bcm, 0x04A2,
1026 (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0900);
1027 bcm43xx_phy_write(bcm, 0x04A0,
1028 (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0700);
1029 bcm43xx_phy_write(bcm, 0x04A2,
1030 (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x000D);
1031 bcm43xx_phy_write(bcm, 0x04A8,
1032 (bcm43xx_phy_read(bcm, 0x04A8) & 0xCFFF) | 0x1000);
1033 bcm43xx_phy_write(bcm, 0x04A8,
1034 (bcm43xx_phy_read(bcm, 0x04A8) & 0xF0FF) | 0x0A00);
1035 bcm43xx_phy_write(bcm, 0x04AB,
1036 (bcm43xx_phy_read(bcm, 0x04AB) & 0xCFFF) | 0x1000);
1037 bcm43xx_phy_write(bcm, 0x04AB,
1038 (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0800);
1039 bcm43xx_phy_write(bcm, 0x04AB,
1040 (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFCF) | 0x0010);
1041 bcm43xx_phy_write(bcm, 0x04AB,
1042 (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFF0) | 0x0006);
1043
1044 bcm43xx_calc_nrssi_slope(bcm);
1045 break;
1046 default:
1047 assert(0);
1048 }
1049}
1050
1051static void
1052bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm,
1053 int mode)
1054{
1055 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1056 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1057 int i = 0;
1058 u16 *stack = radio->interfstack;
1059 u16 tmp, flipped;
1060
1061 switch (mode) {
1062 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
1063 if (phy->rev != 1) {
1064 bcm43xx_phy_write(bcm, 0x042B,
1065 bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
1066 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1067 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000);
1068 break;
1069 }
1070 tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E);
1071 flipped = flip_4bit(tmp);
1072 if ((flipped >> 1) >= 0x000C)
1073 tmp = flipped + 3;
1074 tmp = flip_4bit(tmp);
1075 bcm43xx_radio_write16(bcm, 0x0078, tmp << 1);
1076
1077 bcm43xx_calc_nrssi_threshold(bcm);
1078
1079 if (bcm->current_core->rev < 5) {
1080 bcm43xx_phy_write(bcm, 0x0406, stack_restore());
1081 } else {
1082 bcm43xx_phy_write(bcm, 0x04C0, stack_restore());
1083 bcm43xx_phy_write(bcm, 0x04C1, stack_restore());
1084 }
1085 bcm43xx_phy_write(bcm, 0x042B,
1086 bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
1087
1088 if (!bcm->bad_frames_preempt)
1089 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
1090 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & ~(1 << 11));
1091 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1092 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000);
1093 bcm43xx_phy_write(bcm, 0x04A0, stack_restore());
1094 bcm43xx_phy_write(bcm, 0x04A1, stack_restore());
1095 bcm43xx_phy_write(bcm, 0x04A2, stack_restore());
1096 bcm43xx_phy_write(bcm, 0x04A8, stack_restore());
1097 bcm43xx_phy_write(bcm, 0x04AB, stack_restore());
1098 bcm43xx_phy_write(bcm, 0x04A7, stack_restore());
1099 bcm43xx_phy_write(bcm, 0x04A3, stack_restore());
1100 bcm43xx_phy_write(bcm, 0x04A9, stack_restore());
1101 bcm43xx_phy_write(bcm, 0x0493, stack_restore());
1102 bcm43xx_phy_write(bcm, 0x04AA, stack_restore());
1103 bcm43xx_phy_write(bcm, 0x04AC, stack_restore());
1104 break;
1105 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
1106 if (bcm43xx_phy_read(bcm, 0x0033) != 0x0800)
1107 break;
1108
1109 radio->aci_enable = 0;
1110
1111 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, stack_restore());
1112 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, stack_restore());
1113 if (bcm->current_core->rev < 5) {
1114 bcm43xx_phy_write(bcm, 0x0406, stack_restore());
1115 } else {
1116 bcm43xx_phy_write(bcm, 0x04C0, stack_restore());
1117 bcm43xx_phy_write(bcm, 0x04C1, stack_restore());
1118 }
1119 bcm43xx_phy_write(bcm, 0x0033, stack_restore());
1120 bcm43xx_phy_write(bcm, 0x04A7, stack_restore());
1121 bcm43xx_phy_write(bcm, 0x04A3, stack_restore());
1122 bcm43xx_phy_write(bcm, 0x04A9, stack_restore());
1123 bcm43xx_phy_write(bcm, 0x04AA, stack_restore());
1124 bcm43xx_phy_write(bcm, 0x04AC, stack_restore());
1125 bcm43xx_phy_write(bcm, 0x0493, stack_restore());
1126 bcm43xx_phy_write(bcm, 0x04A1, stack_restore());
1127 bcm43xx_phy_write(bcm, 0x04A0, stack_restore());
1128 bcm43xx_phy_write(bcm, 0x04A2, stack_restore());
1129 bcm43xx_phy_write(bcm, 0x04A8, stack_restore());
1130 bcm43xx_phy_write(bcm, 0x04AB, stack_restore());
1131
1132 bcm43xx_calc_nrssi_slope(bcm);
1133 break;
1134 default:
1135 assert(0);
1136 }
1137}
1138
1139#undef stack_save
1140#undef stack_restore
1141
1142int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm,
1143 int mode)
1144{
1145 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1146 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1147 int currentmode;
1148
1149 if ((phy->type != BCM43xx_PHYTYPE_G) ||
1150 (phy->rev == 0) ||
1151 (!phy->connected))
1152 return -ENODEV;
1153
1154 radio->aci_wlan_automatic = 0;
1155 switch (mode) {
1156 case BCM43xx_RADIO_INTERFMODE_AUTOWLAN:
1157 radio->aci_wlan_automatic = 1;
1158 if (radio->aci_enable)
1159 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
1160 else
1161 mode = BCM43xx_RADIO_INTERFMODE_NONE;
1162 break;
1163 case BCM43xx_RADIO_INTERFMODE_NONE:
1164 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
1165 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
1166 break;
1167 default:
1168 return -EINVAL;
1169 }
1170
1171 currentmode = radio->interfmode;
1172 if (currentmode == mode)
1173 return 0;
1174 if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE)
1175 bcm43xx_radio_interference_mitigation_disable(bcm, currentmode);
1176
1177 if (mode == BCM43xx_RADIO_INTERFMODE_NONE) {
1178 radio->aci_enable = 0;
1179 radio->aci_hw_rssi = 0;
1180 } else
1181 bcm43xx_radio_interference_mitigation_enable(bcm, mode);
1182 radio->interfmode = mode;
1183
1184 return 0;
1185}
1186
1187static u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
1188{
1189 u16 reg, index, ret;
1190
1191 reg = bcm43xx_radio_read16(bcm, 0x0060);
1192 index = (reg & 0x001E) >> 1;
1193 ret = rcc_table[index] << 1;
1194 ret |= (reg & 0x0001);
1195 ret |= 0x0020;
1196
1197 return ret;
1198}
1199
1200u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
1201{
1202 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1203 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1204 u16 backup[19] = { 0 };
1205 u16 ret;
1206 u16 i, j;
1207 u32 tmp1 = 0, tmp2 = 0;
1208
1209 backup[0] = bcm43xx_radio_read16(bcm, 0x0043);
1210 backup[14] = bcm43xx_radio_read16(bcm, 0x0051);
1211 backup[15] = bcm43xx_radio_read16(bcm, 0x0052);
1212 backup[1] = bcm43xx_phy_read(bcm, 0x0015);
1213 backup[16] = bcm43xx_phy_read(bcm, 0x005A);
1214 backup[17] = bcm43xx_phy_read(bcm, 0x0059);
1215 backup[18] = bcm43xx_phy_read(bcm, 0x0058);
1216 if (phy->type == BCM43xx_PHYTYPE_B) {
1217 backup[2] = bcm43xx_phy_read(bcm, 0x0030);
1218 backup[3] = bcm43xx_read16(bcm, 0x03EC);
1219 bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
1220 bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
1221 } else {
1222 if (phy->connected) {
1223 backup[4] = bcm43xx_phy_read(bcm, 0x0811);
1224 backup[5] = bcm43xx_phy_read(bcm, 0x0812);
1225 backup[6] = bcm43xx_phy_read(bcm, 0x0814);
1226 backup[7] = bcm43xx_phy_read(bcm, 0x0815);
1227 backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
1228 backup[9] = bcm43xx_phy_read(bcm, 0x0802);
1229 bcm43xx_phy_write(bcm, 0x0814,
1230 (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
1231 bcm43xx_phy_write(bcm, 0x0815,
1232 (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));
1233 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1234 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
1235 bcm43xx_phy_write(bcm, 0x0802,
1236 (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
1237 bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
1238 bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
1239 }
1240 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
1241 (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
1242 }
1243 backup[10] = bcm43xx_phy_read(bcm, 0x0035);
1244 bcm43xx_phy_write(bcm, 0x0035,
1245 (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
1246 backup[11] = bcm43xx_read16(bcm, 0x03E6);
1247 backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
1248
1249 // Initialization
1250 if (phy->version == 0) {
1251 bcm43xx_write16(bcm, 0x03E6, 0x0122);
1252 } else {
1253 if (phy->version >= 2)
1254 bcm43xx_write16(bcm, 0x03E6, 0x0040);
1255 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
1256 (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
1257 }
1258
1259 ret = bcm43xx_radio_calibrationvalue(bcm);
1260
1261 if (phy->type == BCM43xx_PHYTYPE_B)
1262 bcm43xx_radio_write16(bcm, 0x0078, 0x0003);
1263
1264 bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
1265 bcm43xx_phy_write(bcm, 0x002B, 0x1403);
1266 if (phy->connected)
1267 bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
1268 bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
1269 bcm43xx_radio_write16(bcm, 0x0051,
1270 (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
1271 bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
1272 bcm43xx_radio_write16(bcm, 0x0043,
1273 bcm43xx_radio_read16(bcm, 0x0043) | 0x0009);
1274 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1275
1276 for (i = 0; i < 16; i++) {
1277 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
1278 bcm43xx_phy_write(bcm, 0x0059, 0xC810);
1279 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
1280 if (phy->connected)
1281 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1282 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1283 udelay(10);
1284 if (phy->connected)
1285 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1286 bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
1287 udelay(10);
1288 if (phy->connected)
1289 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1290 bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
1291 udelay(10);
1292 tmp1 += bcm43xx_phy_read(bcm, 0x002D);
1293 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1294 if (phy->connected)
1295 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1296 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1297 }
1298
1299 tmp1++;
1300 tmp1 >>= 9;
1301 udelay(10);
1302 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1303
1304 for (i = 0; i < 16; i++) {
1305 bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020);
1306 backup[13] = bcm43xx_radio_read16(bcm, 0x0078);
1307 udelay(10);
1308 for (j = 0; j < 16; j++) {
1309 bcm43xx_phy_write(bcm, 0x005A, 0x0D80);
1310 bcm43xx_phy_write(bcm, 0x0059, 0xC810);
1311 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
1312 if (phy->connected)
1313 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1314 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1315 udelay(10);
1316 if (phy->connected)
1317 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1318 bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
1319 udelay(10);
1320 if (phy->connected)
1321 bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
1322 bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
1323 udelay(10);
1324 tmp2 += bcm43xx_phy_read(bcm, 0x002D);
1325 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1326 if (phy->connected)
1327 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1328 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1329 }
1330 tmp2++;
1331 tmp2 >>= 8;
1332 if (tmp1 < tmp2)
1333 break;
1334 }
1335
1336 /* Restore the registers */
1337 bcm43xx_phy_write(bcm, 0x0015, backup[1]);
1338 bcm43xx_radio_write16(bcm, 0x0051, backup[14]);
1339 bcm43xx_radio_write16(bcm, 0x0052, backup[15]);
1340 bcm43xx_radio_write16(bcm, 0x0043, backup[0]);
1341 bcm43xx_phy_write(bcm, 0x005A, backup[16]);
1342 bcm43xx_phy_write(bcm, 0x0059, backup[17]);
1343 bcm43xx_phy_write(bcm, 0x0058, backup[18]);
1344 bcm43xx_write16(bcm, 0x03E6, backup[11]);
1345 if (phy->version != 0)
1346 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]);
1347 bcm43xx_phy_write(bcm, 0x0035, backup[10]);
1348 bcm43xx_radio_selectchannel(bcm, radio->channel, 1);
1349 if (phy->type == BCM43xx_PHYTYPE_B) {
1350 bcm43xx_phy_write(bcm, 0x0030, backup[2]);
1351 bcm43xx_write16(bcm, 0x03EC, backup[3]);
1352 } else {
1353 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
1354 (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
1355 if (phy->connected) {
1356 bcm43xx_phy_write(bcm, 0x0811, backup[4]);
1357 bcm43xx_phy_write(bcm, 0x0812, backup[5]);
1358 bcm43xx_phy_write(bcm, 0x0814, backup[6]);
1359 bcm43xx_phy_write(bcm, 0x0815, backup[7]);
1360 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
1361 bcm43xx_phy_write(bcm, 0x0802, backup[9]);
1362 }
1363 }
1364 if (i >= 15)
1365 ret = backup[13];
1366
1367 return ret;
1368}
1369
1370void bcm43xx_radio_init2060(struct bcm43xx_private *bcm)
1371{
1372 int err;
1373
1374 bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
1375 bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
1376 bcm43xx_radio_write16(bcm, 0x0009, 0x0040);
1377 bcm43xx_radio_write16(bcm, 0x0005, 0x00AA);
1378 bcm43xx_radio_write16(bcm, 0x0032, 0x008F);
1379 bcm43xx_radio_write16(bcm, 0x0006, 0x008F);
1380 bcm43xx_radio_write16(bcm, 0x0034, 0x008F);
1381 bcm43xx_radio_write16(bcm, 0x002C, 0x0007);
1382 bcm43xx_radio_write16(bcm, 0x0082, 0x0080);
1383 bcm43xx_radio_write16(bcm, 0x0080, 0x0000);
1384 bcm43xx_radio_write16(bcm, 0x003F, 0x00DA);
1385 bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
1386 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010);
1387 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
1388 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
1389 udelay(400);
1390
1391 bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010);
1392 udelay(400);
1393
1394 bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008);
1395 bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010);
1396 bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
1397 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040);
1398 bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040);
1399 bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008);
1400 bcm43xx_phy_write(bcm, 0x0063, 0xDDC6);
1401 bcm43xx_phy_write(bcm, 0x0069, 0x07BE);
1402 bcm43xx_phy_write(bcm, 0x006A, 0x0000);
1403
1404 err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0);
1405 assert(err == 0);
1406 udelay(1000);
1407}
1408
1409static inline
1410u16 freq_r3A_value(u16 frequency)
1411{
1412 u16 value;
1413
1414 if (frequency < 5091)
1415 value = 0x0040;
1416 else if (frequency < 5321)
1417 value = 0x0000;
1418 else if (frequency < 5806)
1419 value = 0x0080;
1420 else
1421 value = 0x0040;
1422
1423 return value;
1424}
1425
1426void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm)
1427{
1428 static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
1429 static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
1430 u16 tmp = bcm43xx_radio_read16(bcm, 0x001E);
1431 int i, j;
1432
1433 for (i = 0; i < 5; i++) {
1434 for (j = 0; j < 5; j++) {
1435 if (tmp == (data_high[i] << 4 | data_low[j])) {
1436 bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0);
1437 return;
1438 }
1439 }
1440 }
1441}
1442
1443int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
1444 u8 channel,
1445 int synthetic_pu_workaround)
1446{
1447 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1448 u16 r8, tmp;
1449 u16 freq;
1450
1451 if ((radio->manufact == 0x17F) &&
1452 (radio->version == 0x2060) &&
1453 (radio->revision == 1)) {
1454 if (channel > 200)
1455 return -EINVAL;
1456 freq = channel2freq_a(channel);
1457
1458 r8 = bcm43xx_radio_read16(bcm, 0x0008);
1459 bcm43xx_write16(bcm, 0x03F0, freq);
1460 bcm43xx_radio_write16(bcm, 0x0008, r8);
1461
1462 TODO();//TODO: write max channel TX power? to Radio 0x2D
1463 tmp = bcm43xx_radio_read16(bcm, 0x002E);
1464 tmp &= 0x0080;
1465 TODO();//TODO: OR tmp with the Power out estimation for this channel?
1466 bcm43xx_radio_write16(bcm, 0x002E, tmp);
1467
1468 if (freq >= 4920 && freq <= 5500) {
1469 /*
1470 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
1471 * = (freq * 0.025862069
1472 */
1473 r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
1474 }
1475 bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8);
1476 bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8);
1477 bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8);
1478 bcm43xx_radio_write16(bcm, 0x0022,
1479 (bcm43xx_radio_read16(bcm, 0x0022)
1480 & 0x000F) | (r8 << 4));
1481 bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4));
1482 bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4));
1483 bcm43xx_radio_write16(bcm, 0x0008,
1484 (bcm43xx_radio_read16(bcm, 0x0008)
1485 & 0x00F0) | (r8 << 4));
1486 bcm43xx_radio_write16(bcm, 0x0029,
1487 (bcm43xx_radio_read16(bcm, 0x0029)
1488 & 0xFF0F) | 0x00B0);
1489 bcm43xx_radio_write16(bcm, 0x0035, 0x00AA);
1490 bcm43xx_radio_write16(bcm, 0x0036, 0x0085);
1491 bcm43xx_radio_write16(bcm, 0x003A,
1492 (bcm43xx_radio_read16(bcm, 0x003A)
1493 & 0xFF20) | freq_r3A_value(freq));
1494 bcm43xx_radio_write16(bcm, 0x003D,
1495 bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF);
1496 bcm43xx_radio_write16(bcm, 0x0081,
1497 (bcm43xx_radio_read16(bcm, 0x0081)
1498 & 0xFF7F) | 0x0080);
1499 bcm43xx_radio_write16(bcm, 0x0035,
1500 bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF);
1501 bcm43xx_radio_write16(bcm, 0x0035,
1502 (bcm43xx_radio_read16(bcm, 0x0035)
1503 & 0xFFEF) | 0x0010);
1504 bcm43xx_radio_set_tx_iq(bcm);
1505 TODO(); //TODO: TSSI2dbm workaround
1506 bcm43xx_phy_xmitpower(bcm);//FIXME correct?
1507 } else {
1508 if ((channel < 1) || (channel > 14))
1509 return -EINVAL;
1510
1511 if (synthetic_pu_workaround)
1512 bcm43xx_synth_pu_workaround(bcm, channel);
1513
1514 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
1515 channel2freq_bg(channel));
1516
1517 if (channel == 14) {
1518 if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) {
1519 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
1520 BCM43xx_UCODEFLAGS_OFFSET,
1521 bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
1522 BCM43xx_UCODEFLAGS_OFFSET)
1523 & ~(1 << 7));
1524 } else {
1525 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
1526 BCM43xx_UCODEFLAGS_OFFSET,
1527 bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
1528 BCM43xx_UCODEFLAGS_OFFSET)
1529 | (1 << 7));
1530 }
1531 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
1532 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
1533 | (1 << 11));
1534 } else {
1535 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
1536 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
1537 & 0xF7BF);
1538 }
1539 }
1540
1541 radio->channel = channel;
1542 //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
1543 // that 2000 usecs might suffice.
1544 udelay(8000);
1545
1546 return 0;
1547}
1548
1549void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val)
1550{
1551 u16 tmp;
1552
1553 val <<= 8;
1554 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF;
1555 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val);
1556 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF;
1557 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val);
1558 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF;
1559 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val);
1560}
1561
1562/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
1563static u16 bcm43xx_get_txgain_base_band(u16 txpower)
1564{
1565 u16 ret;
1566
1567 assert(txpower <= 63);
1568
1569 if (txpower >= 54)
1570 ret = 2;
1571 else if (txpower >= 49)
1572 ret = 4;
1573 else if (txpower >= 44)
1574 ret = 5;
1575 else
1576 ret = 6;
1577
1578 return ret;
1579}
1580
1581/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
1582static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower)
1583{
1584 u16 ret;
1585
1586 assert(txpower <= 63);
1587
1588 if (txpower >= 32)
1589 ret = 0;
1590 else if (txpower >= 25)
1591 ret = 1;
1592 else if (txpower >= 20)
1593 ret = 2;
1594 else if (txpower >= 12)
1595 ret = 3;
1596 else
1597 ret = 4;
1598
1599 return ret;
1600}
1601
1602/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
1603static u16 bcm43xx_get_txgain_dac(u16 txpower)
1604{
1605 u16 ret;
1606
1607 assert(txpower <= 63);
1608
1609 if (txpower >= 54)
1610 ret = txpower - 53;
1611 else if (txpower >= 49)
1612 ret = txpower - 42;
1613 else if (txpower >= 44)
1614 ret = txpower - 37;
1615 else if (txpower >= 32)
1616 ret = txpower - 32;
1617 else if (txpower >= 25)
1618 ret = txpower - 20;
1619 else if (txpower >= 20)
1620 ret = txpower - 13;
1621 else if (txpower >= 12)
1622 ret = txpower - 8;
1623 else
1624 ret = txpower;
1625
1626 return ret;
1627}
1628
1629void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower)
1630{
1631 u16 pamp, base, dac, ilt;
1632
1633 txpower = limit_value(txpower, 0, 63);
1634
1635 pamp = bcm43xx_get_txgain_freq_power_amp(txpower);
1636 pamp <<= 5;
1637 pamp &= 0x00E0;
1638 bcm43xx_phy_write(bcm, 0x0019, pamp);
1639
1640 base = bcm43xx_get_txgain_base_band(txpower);
1641 base &= 0x000F;
1642 bcm43xx_phy_write(bcm, 0x0017, base | 0x0020);
1643
1644 ilt = bcm43xx_ilt_read16(bcm, 0x3001);
1645 ilt &= 0x0007;
1646
1647 dac = bcm43xx_get_txgain_dac(txpower);
1648 dac <<= 3;
1649 dac |= ilt;
1650
1651 bcm43xx_ilt_write16(bcm, 0x3001, dac);
1652
1653 bcm->current_core->radio->txpower[0] = txpower;
1654
1655 TODO();
1656 //TODO: FuncPlaceholder (Adjust BB loft cancel)
1657}
1658
1659void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
1660 u16 baseband_attenuation, u16 radio_attenuation,
1661 u16 txpower)
1662{
1663 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1664 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1665
1666 if (baseband_attenuation == 0xFFFF)
1667 baseband_attenuation = radio->txpower[0];
1668 else
1669 radio->txpower[0] = baseband_attenuation;
1670 if (radio_attenuation == 0xFFFF)
1671 radio_attenuation = radio->txpower[1];
1672 else
1673 radio->txpower[1] = radio_attenuation;
1674 if (txpower == 0xFFFF)
1675 txpower = radio->txpower[2];
1676 else
1677 radio->txpower[2] = txpower;
1678
1679 assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11);
1680 if (radio->revision < 6)
1681 assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9);
1682 else
1683 assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31);
1684 assert(/*txpower >= 0 &&*/ txpower <= 7);
1685
1686 bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation);
1687 bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation);
1688 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation);
1689 if (radio->version == 0x2050) {
1690 bcm43xx_radio_write16(bcm, 0x0052,
1691 (bcm43xx_radio_read16(bcm, 0x0052) & 0xFF8F)
1692 | (txpower << 4));
1693 }
1694 if (phy->type == BCM43xx_PHYTYPE_G)
1695 bcm43xx_phy_lo_adjust(bcm, 0);
1696}
1697
1698
1699void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
1700{
1701 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1702 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1703 int err;
1704
1705 if (radio->enabled)
1706 return;
1707
1708 switch (phy->type) {
1709 case BCM43xx_PHYTYPE_A:
1710 bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
1711 bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
1712 bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7);
1713 bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7);
1714 bcm43xx_radio_init2060(bcm);
1715 break;
1716 case BCM43xx_PHYTYPE_B:
1717 case BCM43xx_PHYTYPE_G:
1718 bcm43xx_phy_write(bcm, 0x0015, 0x8000);
1719 bcm43xx_phy_write(bcm, 0x0015, 0xCC00);
1720 bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000));
1721 err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1);
1722 assert(err == 0);
1723 break;
1724 default:
1725 assert(0);
1726 }
1727 radio->enabled = 1;
1728 dprintk(KERN_INFO PFX "Radio turned on\n");
1729}
1730
1731void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
1732{
1733 struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
1734 struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
1735
1736 if (phy->type == BCM43xx_PHYTYPE_A) {
1737 bcm43xx_radio_write16(bcm, 0x0004, 0x00FF);
1738 bcm43xx_radio_write16(bcm, 0x0005, 0x00FB);
1739 bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008);
1740 bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008);
1741 }
1742 if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) {
1743 bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C);
1744 bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73);
1745 } else
1746 bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
1747 radio->enabled = 0;
1748 dprintk(KERN_INFO PFX "Radio turned off\n");
1749}
1750
1751void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
1752{
1753 switch (bcm->current_core->phy->type) {
1754 case BCM43xx_PHYTYPE_A:
1755 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F);
1756 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F);
1757 break;
1758 case BCM43xx_PHYTYPE_B:
1759 case BCM43xx_PHYTYPE_G:
1760 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F);
1761 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F);
1762 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F);
1763 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F);
1764 break;
1765 }
1766}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
new file mode 100644
index 000000000000..89fe29282140
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -0,0 +1,93 @@
1/*
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#ifndef BCM43xx_RADIO_H_
32#define BCM43xx_RADIO_H_
33
34#include "bcm43xx.h"
35
36
37#define BCM43xx_RADIO_DEFAULT_CHANNEL_A 36
38#define BCM43xx_RADIO_DEFAULT_CHANNEL_BG 6
39
40/* Force antenna 0. */
41#define BCM43xx_RADIO_TXANTENNA_0 0
42/* Force antenna 1. */
43#define BCM43xx_RADIO_TXANTENNA_1 1
44/* Use the RX antenna, that was selected for the most recently
45 * received good PLCP header.
46 */
47#define BCM43xx_RADIO_TXANTENNA_LASTPLCP 3
48#define BCM43xx_RADIO_TXANTENNA_DEFAULT BCM43xx_RADIO_TXANTENNA_LASTPLCP
49
50#define BCM43xx_RADIO_INTERFMODE_NONE 0
51#define BCM43xx_RADIO_INTERFMODE_NONWLAN 1
52#define BCM43xx_RADIO_INTERFMODE_MANUALWLAN 2
53#define BCM43xx_RADIO_INTERFMODE_AUTOWLAN 3
54
55
56void bcm43xx_radio_lock(struct bcm43xx_private *bcm);
57void bcm43xx_radio_unlock(struct bcm43xx_private *bcm);
58
59u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset);
60void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val);
61
62u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm);
63void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
64
65void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
66void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
67
68int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
69 int synthetic_pu_workaround);
70
71void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower);
72void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
73 u16 baseband_attenuation, u16 attenuation,
74 u16 txpower);
75void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val);
76
77void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm);
78
79u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel);
80u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm);
81
82int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode);
83
84void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm);
85void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm);
86s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset);
87void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val);
88void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val);
89void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm);
90
91void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm);
92
93#endif /* BCM43xx_RADIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
new file mode 100644
index 000000000000..fe6409a90901
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -0,0 +1,1099 @@
1/*
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/wireless.h>
32#include <net/iw_handler.h>
33#include <net/ieee80211softmac.h>
34#include <net/ieee80211softmac_wx.h>
35#include <linux/capability.h>
36#include <linux/sched.h> /* for capable() */
37#include <linux/delay.h>
38
39#include "bcm43xx.h"
40#include "bcm43xx_wx.h"
41#include "bcm43xx_main.h"
42#include "bcm43xx_radio.h"
43
44/* Define to enable a printk on each wx handler function invocation */
45//#define BCM43xx_WX_DEBUG
46
47
48#ifdef BCM43xx_WX_DEBUG
49# define printk_wx printk
50#else
51# define printk_wx(x...) do { /* nothing */ } while (0)
52#endif
53#define wx_enter() printk_wx(KERN_INFO PFX "WX handler called: %s\n", __FUNCTION__);
54
55#define MAX_WX_STRING 80
56
57
58static int bcm43xx_wx_get_name(struct net_device *net_dev,
59 struct iw_request_info *info,
60 union iwreq_data *data,
61 char *extra)
62{
63 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
64 unsigned long flags;
65 int i, nr_80211;
66 struct bcm43xx_phyinfo *phy;
67 char suffix[7] = { 0 };
68 int have_a = 0, have_b = 0, have_g = 0;
69
70 wx_enter();
71
72 spin_lock_irqsave(&bcm->lock, flags);
73 nr_80211 = bcm43xx_num_80211_cores(bcm);
74 for (i = 0; i < nr_80211; i++) {
75 phy = bcm->phy + i;
76 switch (phy->type) {
77 case BCM43xx_PHYTYPE_A:
78 have_a = 1;
79 break;
80 case BCM43xx_PHYTYPE_G:
81 have_g = 1;
82 case BCM43xx_PHYTYPE_B:
83 have_b = 1;
84 break;
85 default:
86 assert(0);
87 }
88 }
89 spin_unlock_irqrestore(&bcm->lock, flags);
90
91 i = 0;
92 if (have_a) {
93 suffix[i++] = 'a';
94 suffix[i++] = '/';
95 }
96 if (have_b) {
97 suffix[i++] = 'b';
98 suffix[i++] = '/';
99 }
100 if (have_g) {
101 suffix[i++] = 'g';
102 suffix[i++] = '/';
103 }
104 if (i != 0)
105 suffix[i - 1] = '\0';
106
107 snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
108
109 return 0;
110}
111
112static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
113 struct iw_request_info *info,
114 union iwreq_data *data,
115 char *extra)
116{
117 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
118 struct ieee80211softmac_device *softmac = bcm->softmac;
119 unsigned long flags;
120 u8 channel;
121 int freq;
122 int err = 0;
123
124 wx_enter();
125
126 if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
127 channel = data->freq.m;
128 freq = bcm43xx_channel_to_freq(bcm, channel);
129 } else {
130 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
131 freq = data->freq.m;
132 }
133 if (!bcm43xx_is_valid_channel(bcm, channel))
134 return -EINVAL;
135
136 spin_lock_irqsave(&bcm->lock, flags);
137 if (bcm->initialized) {
138 //ieee80211softmac_disassoc(softmac, $REASON);
139 bcm43xx_mac_suspend(bcm);
140 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
141 bcm43xx_mac_enable(bcm);
142 } else
143 bcm->current_core->radio->initial_channel = channel;
144 spin_unlock_irqrestore(&bcm->lock, flags);
145 if (!err)
146 printk_wx(KERN_INFO PFX "Selected channel: %d\n", channel);
147
148 return err;
149}
150
151static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
152 struct iw_request_info *info,
153 union iwreq_data *data,
154 char *extra)
155{
156 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
157 unsigned long flags;
158 int err = -ENODEV;
159 u16 channel;
160
161 wx_enter();
162
163 spin_lock_irqsave(&bcm->lock, flags);
164 channel = bcm->current_core->radio->channel;
165 if (channel == 0xFF) {
166 assert(!bcm->initialized);
167 channel = bcm->current_core->radio->initial_channel;
168 if (channel == 0xFF)
169 goto out_unlock;
170 }
171 assert(channel > 0 && channel <= 1000);
172 data->freq.e = 1;
173 data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
174 data->freq.flags = 1;
175
176 err = 0;
177out_unlock:
178 spin_unlock_irqrestore(&bcm->lock, flags);
179
180 return err;
181}
182
183static int bcm43xx_wx_set_mode(struct net_device *net_dev,
184 struct iw_request_info *info,
185 union iwreq_data *data,
186 char *extra)
187{
188 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
189 unsigned long flags;
190 int mode;
191
192 wx_enter();
193
194 mode = data->mode;
195 if (mode == IW_MODE_AUTO)
196 mode = BCM43xx_INITIAL_IWMODE;
197
198 spin_lock_irqsave(&bcm->lock, flags);
199 if (bcm->ieee->iw_mode != mode)
200 bcm43xx_set_iwmode(bcm, mode);
201 spin_unlock_irqrestore(&bcm->lock, flags);
202
203 return 0;
204}
205
206static int bcm43xx_wx_get_mode(struct net_device *net_dev,
207 struct iw_request_info *info,
208 union iwreq_data *data,
209 char *extra)
210{
211 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
212 unsigned long flags;
213
214 wx_enter();
215
216 spin_lock_irqsave(&bcm->lock, flags);
217 data->mode = bcm->ieee->iw_mode;
218 spin_unlock_irqrestore(&bcm->lock, flags);
219
220 return 0;
221}
222
223static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev,
224 struct iw_request_info *info,
225 union iwreq_data *data,
226 char *extra)
227{
228 wx_enter();
229 /*TODO*/
230 return 0;
231}
232
233static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev,
234 struct iw_request_info *info,
235 union iwreq_data *data,
236 char *extra)
237{
238 wx_enter();
239 /*TODO*/
240 return 0;
241}
242
243static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
244 struct iw_request_info *info,
245 union iwreq_data *data,
246 char *extra)
247{
248 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
249 struct iw_range *range = (struct iw_range *)extra;
250 const struct ieee80211_geo *geo;
251 unsigned long flags;
252 int i, j;
253
254 wx_enter();
255
256 data->data.length = sizeof(*range);
257 memset(range, 0, sizeof(*range));
258
259 //TODO: What about 802.11b?
260 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
261 range->throughput = 27 * 1000 * 1000;
262
263 range->max_qual.qual = 100;
264 /* TODO: Real max RSSI */
265 range->max_qual.level = 0;
266 range->max_qual.noise = 0;
267 range->max_qual.updated = 7;
268
269 range->avg_qual.qual = 70;
270 range->avg_qual.level = 0;
271 range->avg_qual.noise = 0;
272 range->avg_qual.updated = 7;
273
274 range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
275 range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
276 range->min_frag = MIN_FRAG_THRESHOLD;
277 range->max_frag = MAX_FRAG_THRESHOLD;
278
279 range->encoding_size[0] = 5;
280 range->encoding_size[1] = 13;
281 range->num_encoding_sizes = 2;
282 range->max_encoding_tokens = WEP_KEYS;
283
284 range->we_version_compiled = WIRELESS_EXT;
285 range->we_version_source = 16;
286
287 spin_lock_irqsave(&bcm->lock, flags);
288
289 range->num_bitrates = 0;
290 i = 0;
291 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ||
292 bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
293 range->num_bitrates = 8;
294 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
295 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
296 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
297 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
298 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
299 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
300 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
301 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
302 }
303 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B ||
304 bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
305 range->num_bitrates += 4;
306 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
307 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
308 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
309 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
310 }
311
312 geo = ieee80211_get_geo(bcm->ieee);
313 range->num_channels = geo->a_channels + geo->bg_channels;
314 j = 0;
315 for (i = 0; i < geo->a_channels; i++) {
316 if (j == IW_MAX_FREQUENCIES)
317 break;
318 range->freq[j].i = j + 1;
319 range->freq[j].m = geo->a[i].freq;//FIXME?
320 range->freq[j].e = 1;
321 j++;
322 }
323 for (i = 0; i < geo->bg_channels; i++) {
324 if (j == IW_MAX_FREQUENCIES)
325 break;
326 range->freq[j].i = j + 1;
327 range->freq[j].m = geo->bg[i].freq;//FIXME?
328 range->freq[j].e = 1;
329 j++;
330 }
331 range->num_frequency = j;
332
333 spin_unlock_irqrestore(&bcm->lock, flags);
334
335 return 0;
336}
337
338static int bcm43xx_wx_set_nick(struct net_device *net_dev,
339 struct iw_request_info *info,
340 union iwreq_data *data,
341 char *extra)
342{
343 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
344 unsigned long flags;
345 size_t len;
346
347 wx_enter();
348
349 spin_lock_irqsave(&bcm->lock, flags);
350 len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
351 memcpy(bcm->nick, extra, len);
352 bcm->nick[len] = '\0';
353 spin_unlock_irqrestore(&bcm->lock, flags);
354
355 return 0;
356}
357
358static int bcm43xx_wx_get_nick(struct net_device *net_dev,
359 struct iw_request_info *info,
360 union iwreq_data *data,
361 char *extra)
362{
363 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
364 unsigned long flags;
365 size_t len;
366
367 wx_enter();
368
369 spin_lock_irqsave(&bcm->lock, flags);
370 len = strlen(bcm->nick) + 1;
371 memcpy(extra, bcm->nick, len);
372 data->data.length = (__u16)len;
373 data->data.flags = 1;
374 spin_unlock_irqrestore(&bcm->lock, flags);
375
376 return 0;
377}
378
379static int bcm43xx_wx_set_rts(struct net_device *net_dev,
380 struct iw_request_info *info,
381 union iwreq_data *data,
382 char *extra)
383{
384 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
385 unsigned long flags;
386 int err = -EINVAL;
387
388 wx_enter();
389
390 spin_lock_irqsave(&bcm->lock, flags);
391 if (data->rts.disabled) {
392 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
393 err = 0;
394 } else {
395 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
396 data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
397 bcm->rts_threshold = data->rts.value;
398 err = 0;
399 }
400 }
401 spin_unlock_irqrestore(&bcm->lock, flags);
402
403 return err;
404}
405
406static int bcm43xx_wx_get_rts(struct net_device *net_dev,
407 struct iw_request_info *info,
408 union iwreq_data *data,
409 char *extra)
410{
411 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
412 unsigned long flags;
413
414 wx_enter();
415
416 spin_lock_irqsave(&bcm->lock, flags);
417 data->rts.value = bcm->rts_threshold;
418 data->rts.fixed = 0;
419 data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
420 spin_unlock_irqrestore(&bcm->lock, flags);
421
422 return 0;
423}
424
425static int bcm43xx_wx_set_frag(struct net_device *net_dev,
426 struct iw_request_info *info,
427 union iwreq_data *data,
428 char *extra)
429{
430 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
431 unsigned long flags;
432 int err = -EINVAL;
433
434 wx_enter();
435
436 spin_lock_irqsave(&bcm->lock, flags);
437 if (data->frag.disabled) {
438 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
439 err = 0;
440 } else {
441 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
442 data->frag.value <= MAX_FRAG_THRESHOLD) {
443 bcm->ieee->fts = data->frag.value & ~0x1;
444 err = 0;
445 }
446 }
447 spin_unlock_irqrestore(&bcm->lock, flags);
448
449 return err;
450}
451
452static int bcm43xx_wx_get_frag(struct net_device *net_dev,
453 struct iw_request_info *info,
454 union iwreq_data *data,
455 char *extra)
456{
457 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
458 unsigned long flags;
459
460 wx_enter();
461
462 spin_lock_irqsave(&bcm->lock, flags);
463 data->frag.value = bcm->ieee->fts;
464 data->frag.fixed = 0;
465 data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
466 spin_unlock_irqrestore(&bcm->lock, flags);
467
468 return 0;
469}
470
471static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
472 struct iw_request_info *info,
473 union iwreq_data *data,
474 char *extra)
475{
476 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
477 unsigned long flags;
478 int err = -ENODEV;
479
480 wx_enter();
481
482 spin_lock_irqsave(&bcm->lock, flags);
483 if (!bcm->initialized)
484 goto out_unlock;
485 if (data->power.disabled != (!(bcm->current_core->radio->enabled))) {
486 if (data->power.disabled)
487 bcm43xx_radio_turn_off(bcm);
488 else
489 bcm43xx_radio_turn_on(bcm);
490 }
491 //TODO: set txpower.
492 err = 0;
493
494out_unlock:
495 spin_unlock_irqrestore(&bcm->lock, flags);
496
497 return err;
498}
499
500static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
501 struct iw_request_info *info,
502 union iwreq_data *data,
503 char *extra)
504{
505 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
506 unsigned long flags;
507
508 wx_enter();
509
510 spin_lock_irqsave(&bcm->lock, flags);
511//TODO data->power.value = ???
512 data->power.fixed = 1;
513 data->power.flags = IW_TXPOW_DBM;
514 data->power.disabled = !(bcm->current_core->radio->enabled);
515 spin_unlock_irqrestore(&bcm->lock, flags);
516
517 return 0;
518}
519
520static int bcm43xx_wx_set_retry(struct net_device *net_dev,
521 struct iw_request_info *info,
522 union iwreq_data *data,
523 char *extra)
524{
525 wx_enter();
526 /*TODO*/
527 return 0;
528}
529
530static int bcm43xx_wx_get_retry(struct net_device *net_dev,
531 struct iw_request_info *info,
532 union iwreq_data *data,
533 char *extra)
534{
535 wx_enter();
536 /*TODO*/
537 return 0;
538}
539
540static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
541 struct iw_request_info *info,
542 union iwreq_data *data,
543 char *extra)
544{
545 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
546 int err;
547
548 wx_enter();
549
550 err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
551
552 return err;
553}
554
555static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
556 struct iw_request_info *info,
557 union iwreq_data *data,
558 char *extra)
559{
560 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
561 int err;
562
563 wx_enter();
564
565 err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
566
567 return err;
568}
569
570static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
571 struct iw_request_info *info,
572 union iwreq_data *data,
573 char *extra)
574{
575 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
576 int err;
577
578 wx_enter();
579
580 err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
581
582 return err;
583}
584
585static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
586 struct iw_request_info *info,
587 union iwreq_data *data,
588 char *extra)
589{
590 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
591 int err;
592
593 wx_enter();
594
595 err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
596
597 return err;
598}
599
600static int bcm43xx_wx_set_power(struct net_device *net_dev,
601 struct iw_request_info *info,
602 union iwreq_data *data,
603 char *extra)
604{
605 wx_enter();
606 /*TODO*/
607 return 0;
608}
609
610static int bcm43xx_wx_get_power(struct net_device *net_dev,
611 struct iw_request_info *info,
612 union iwreq_data *data,
613 char *extra)
614{
615 wx_enter();
616 /*TODO*/
617 return 0;
618}
619
620static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
621 struct iw_request_info *info,
622 union iwreq_data *data,
623 char *extra)
624{
625 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
626 unsigned long flags;
627 int mode, err = 0;
628
629 wx_enter();
630
631 mode = *((int *)extra);
632 switch (mode) {
633 case 0:
634 mode = BCM43xx_RADIO_INTERFMODE_NONE;
635 break;
636 case 1:
637 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
638 break;
639 case 2:
640 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
641 break;
642 case 3:
643 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
644 break;
645 default:
646 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
647 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
648 "3 => Auto-WLAN\n");
649 return -EINVAL;
650 }
651
652 spin_lock_irqsave(&bcm->lock, flags);
653 if (bcm->initialized) {
654 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
655 if (err) {
656 printk(KERN_ERR PFX "Interference Mitigation not "
657 "supported by device\n");
658 }
659 } else {
660 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
661 printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
662 "not supported while the interface is down.\n");
663 err = -ENODEV;
664 } else
665 bcm->current_core->radio->interfmode = mode;
666 }
667 spin_unlock_irqrestore(&bcm->lock, flags);
668
669 return err;
670}
671
672static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
673 struct iw_request_info *info,
674 union iwreq_data *data,
675 char *extra)
676{
677 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
678 unsigned long flags;
679 int mode;
680
681 wx_enter();
682
683 spin_lock_irqsave(&bcm->lock, flags);
684 mode = bcm->current_core->radio->interfmode;
685 spin_unlock_irqrestore(&bcm->lock, flags);
686
687 switch (mode) {
688 case BCM43xx_RADIO_INTERFMODE_NONE:
689 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
690 break;
691 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
692 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
693 break;
694 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
695 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
696 break;
697 default:
698 assert(0);
699 }
700 data->data.length = strlen(extra) + 1;
701
702 return 0;
703}
704
705static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
706 struct iw_request_info *info,
707 union iwreq_data *data,
708 char *extra)
709{
710 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
711 unsigned long flags;
712 int on;
713
714 wx_enter();
715
716 on = *((int *)extra);
717 spin_lock_irqsave(&bcm->lock, flags);
718 bcm->short_preamble = !!on;
719 spin_unlock_irqrestore(&bcm->lock, flags);
720
721 return 0;
722}
723
724static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
725 struct iw_request_info *info,
726 union iwreq_data *data,
727 char *extra)
728{
729 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
730 unsigned long flags;
731 int on;
732
733 wx_enter();
734
735 spin_lock_irqsave(&bcm->lock, flags);
736 on = bcm->short_preamble;
737 spin_unlock_irqrestore(&bcm->lock, flags);
738
739 if (on)
740 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
741 else
742 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
743 data->data.length = strlen(extra) + 1;
744
745 return 0;
746}
747
748static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
749 struct iw_request_info *info,
750 union iwreq_data *data,
751 char *extra)
752{
753 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
754 unsigned long flags;
755 int on;
756
757 wx_enter();
758
759 on = *((int *)extra);
760 spin_lock_irqsave(&bcm->lock, flags);
761 bcm->ieee->host_encrypt = !!on;
762 bcm->ieee->host_decrypt = !!on;
763 bcm->ieee->host_build_iv = !on;
764
765 spin_unlock_irqrestore(&bcm->lock, flags);
766
767 return 0;
768}
769
770static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
771 struct iw_request_info *info,
772 union iwreq_data *data,
773 char *extra)
774{
775 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
776 unsigned long flags;
777 int on;
778
779 wx_enter();
780
781 spin_lock_irqsave(&bcm->lock, flags);
782 on = bcm->ieee->host_encrypt;
783 spin_unlock_irqrestore(&bcm->lock, flags);
784
785 if (on)
786 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
787 else
788 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
789 data->data.length = strlen(extra + 1);
790
791 return 0;
792}
793
794/* Enough buffer to hold a hexdump of the sprom data. */
795#define SPROM_BUFFERSIZE 512
796
797static int sprom2hex(const u16 *sprom, char *dump)
798{
799 int i, pos = 0;
800
801 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
802 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
803 "%04X", swab16(sprom[i]) & 0xFFFF);
804 }
805
806 return pos + 1;
807}
808
809static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
810{
811 char tmp[5] = { 0 };
812 int cnt = 0;
813 unsigned long parsed;
814 u8 crc, expected_crc;
815
816 if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
817 return -EINVAL;
818 while (cnt < BCM43xx_SPROM_SIZE) {
819 memcpy(tmp, dump, 4);
820 dump += 4;
821 parsed = simple_strtoul(tmp, NULL, 16);
822 sprom[cnt++] = swab16((u16)parsed);
823 }
824
825 crc = bcm43xx_sprom_crc(sprom);
826 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
827 if (crc != expected_crc) {
828 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
829 return -EINVAL;
830 }
831
832 return 0;
833}
834
835static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
836 struct iw_request_info *info,
837 union iwreq_data *data,
838 char *extra)
839{
840 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
841 int err = -EPERM, i;
842 u16 *sprom;
843 unsigned long flags;
844
845 if (!capable(CAP_SYS_RAWIO))
846 goto out;
847
848 err = -ENOMEM;
849 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
850 GFP_KERNEL);
851 if (!sprom)
852 goto out;
853
854 spin_lock_irqsave(&bcm->lock, flags);
855 err = -ENODEV;
856 if (!bcm->initialized) {
857 spin_unlock_irqrestore(&bcm->lock, flags);
858 goto out_kfree;
859 }
860 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
861 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
862 spin_unlock_irqrestore(&bcm->lock, flags);
863
864 data->data.length = sprom2hex(sprom, extra);
865
866 err = 0;
867out_kfree:
868 kfree(sprom);
869out:
870 return err;
871}
872
873static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
874 struct iw_request_info *info,
875 union iwreq_data *data,
876 char *extra)
877{
878 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
879 int err = -EPERM;
880 u16 *sprom;
881 unsigned long flags;
882 char *input;
883 unsigned int len;
884 u32 spromctl;
885 int i;
886
887 if (!capable(CAP_SYS_RAWIO))
888 goto out;
889
890 err = -ENOMEM;
891 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
892 GFP_KERNEL);
893 if (!sprom)
894 goto out;
895
896 len = data->data.length;
897 extra[len - 1] = '\0';
898 input = strchr(extra, ':');
899 if (input) {
900 input++;
901 len -= input - extra;
902 } else
903 input = extra;
904 err = hex2sprom(sprom, input, len);
905 if (err)
906 goto out_kfree;
907
908 spin_lock_irqsave(&bcm->lock, flags);
909 err = -ENODEV;
910 if (!bcm->initialized) {
911 spin_unlock_irqrestore(&bcm->lock, flags);
912 goto out_kfree;
913 }
914
915 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
916 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
917 if (err) {
918 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
919 goto out_unlock;
920 }
921 spromctl |= 0x10; /* SPROM WRITE enable. */
922 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
923 if (err) {
924 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
925 goto out_unlock;
926 }
927 /* We must burn lots of CPU cycles here, but that does not
928 * really matter as one does not write the SPROM every other minute...
929 */
930 printk(KERN_INFO PFX "[ 0%%");
931 mdelay(500);
932 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
933 if (i == 16)
934 printk("25%%");
935 else if (i == 32)
936 printk("50%%");
937 else if (i == 48)
938 printk("75%%");
939 else if (i % 2)
940 printk(".");
941//TODO bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
942 mdelay(20);
943 }
944 spromctl &= ~0x10; /* SPROM WRITE enable. */
945 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
946 if (err) {
947 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
948 goto out_unlock;
949 }
950 mdelay(500);
951 printk("100%% ]\n");
952 printk(KERN_INFO PFX "SPROM written.\n");
953 err = 0;
954out_unlock:
955 spin_unlock_irqrestore(&bcm->lock, flags);
956out_kfree:
957 kfree(sprom);
958out:
959 return err;
960}
961
962
963#ifdef WX
964# undef WX
965#endif
966#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
967static const iw_handler bcm43xx_wx_handlers[] = {
968 /* Wireless Identification */
969 WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
970 /* Basic operations */
971 WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
972 WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
973 WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
974 WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
975 /* Informative stuff */
976 WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
977 /* Access Point manipulation */
978 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
979 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
980 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
981 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
982 /* 802.11 specific support */
983 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
984 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
985 WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
986 WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
987 /* Other parameters */
988 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
989 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
990 WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
991 WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
992 WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
993 WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
994 WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
995 WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
996//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
997//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
998 /* Encoding */
999 WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
1000 WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
1001 WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
1002 WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
1003 /* Power saving */
1004//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
1005//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
1006 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
1007 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
1008 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
1009 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
1010};
1011#undef WX
1012
1013static const iw_handler bcm43xx_priv_wx_handlers[] = {
1014 /* Set Interference Mitigation Mode. */
1015 bcm43xx_wx_set_interfmode,
1016 /* Get Interference Mitigation Mode. */
1017 bcm43xx_wx_get_interfmode,
1018 /* Enable/Disable Short Preamble mode. */
1019 bcm43xx_wx_set_shortpreamble,
1020 /* Get Short Preamble mode. */
1021 bcm43xx_wx_get_shortpreamble,
1022 /* Enable/Disable Software Encryption mode */
1023 bcm43xx_wx_set_swencryption,
1024 /* Get Software Encryption mode */
1025 bcm43xx_wx_get_swencryption,
1026 /* Write SRPROM data. */
1027 bcm43xx_wx_sprom_write,
1028 /* Read SPROM data. */
1029 bcm43xx_wx_sprom_read,
1030};
1031
1032#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
1033#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
1034#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
1035#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
1036#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
1037#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
1038#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
1039#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
1040
1041#define PRIV_WX_DUMMY(ioctl) \
1042 { \
1043 .cmd = (ioctl), \
1044 .name = "__unused" \
1045 }
1046
1047static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
1048 {
1049 .cmd = PRIV_WX_SET_INTERFMODE,
1050 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1051 .name = "set_interfmode",
1052 },
1053 {
1054 .cmd = PRIV_WX_GET_INTERFMODE,
1055 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1056 .name = "get_interfmode",
1057 },
1058 {
1059 .cmd = PRIV_WX_SET_SHORTPREAMBLE,
1060 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1061 .name = "set_shortpreambl",
1062 },
1063 {
1064 .cmd = PRIV_WX_GET_SHORTPREAMBLE,
1065 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1066 .name = "get_shortpreambl",
1067 },
1068 {
1069 .cmd = PRIV_WX_SET_SWENCRYPTION,
1070 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1071 .name = "set_swencryption",
1072 },
1073 {
1074 .cmd = PRIV_WX_GET_SWENCRYPTION,
1075 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1076 .name = "get_swencryption",
1077 },
1078 {
1079 .cmd = PRIV_WX_SPROM_WRITE,
1080 .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
1081 .name = "write_sprom",
1082 },
1083 {
1084 .cmd = PRIV_WX_SPROM_READ,
1085 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
1086 .name = "read_sprom",
1087 },
1088};
1089
1090const struct iw_handler_def bcm43xx_wx_handlers_def = {
1091 .standard = bcm43xx_wx_handlers,
1092 .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
1093 .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
1094 .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
1095 .private = bcm43xx_priv_wx_handlers,
1096 .private_args = bcm43xx_priv_wx_args,
1097};
1098
1099/* vim: set ts=8 sw=8 sts=8: */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.h b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h
new file mode 100644
index 000000000000..1f29ff3aa4c3
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h
@@ -0,0 +1,36 @@
1/*
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#ifndef BCM43xx_WX_H_
32#define BCM43xx_WX_H_
33
34extern const struct iw_handler_def bcm43xx_wx_handlers_def;
35
36#endif /* BCM43xx_WX_H_ */