aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-03-29 17:30:19 -0500
committerJeff Garzik <jeff@garzik.org>2006-03-29 17:30:19 -0500
commite21a2b0cc5849e76434b37aff3a4b502c772f191 (patch)
tree2fad2f2025ca1d9e5bc88d4e835e07967b8fd762 /drivers/net/wireless/bcm43xx
parent8a89334caf80bb7c86383b73fd5a528cb88c696f (diff)
parent2638fed7ccb07ff43cdc109dd78e821efb629995 (diff)
Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
Diffstat (limited to 'drivers/net/wireless/bcm43xx')
-rw-r--r--drivers/net/wireless/bcm43xx/Kconfig62
-rw-r--r--drivers/net/wireless/bcm43xx/Makefile12
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h926
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c499
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h117
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.c968
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.h218
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c50
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h8
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ilt.c337
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ilt.h32
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c293
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.h56
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c3973
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h168
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c2345
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.h74
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c606
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.h138
-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.c2026
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.h99
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c322
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h25
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c1002
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.h36
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c582
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.h156
29 files changed, 15535 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
new file mode 100644
index 000000000000..418465600a77
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/Kconfig
@@ -0,0 +1,62 @@
1config BCM43XX
2 tristate "Broadcom BCM43xx wireless support"
3 depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
4 select FW_LOADER
5 ---help---
6 This is an experimental driver for the Broadcom 43xx wireless chip,
7 found in the Apple Airport Extreme and various other devices.
8
9config BCM43XX_DEBUG
10 bool "Broadcom BCM43xx debugging (RECOMMENDED)"
11 depends on BCM43XX
12 default y
13 ---help---
14 Broadcom 43xx debugging messages.
15 Say Y, because the driver is still very experimental and
16 this will help you get it running.
17
18config BCM43XX_DMA
19 bool
20config BCM43XX_PIO
21 bool
22
23choice
24 prompt "BCM43xx data transfer mode"
25 depends on BCM43XX
26 default BCM43XX_DMA_AND_PIO_MODE
27
28config BCM43XX_DMA_AND_PIO_MODE
29 bool "DMA + PIO"
30 select BCM43XX_DMA
31 select BCM43XX_PIO
32 ---help---
33 Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
34 data transfer modes.
35 The actually used mode is selectable through the module
36 parameter "pio". If the module parameter is pio=0, DMA is used.
37 Otherwise PIO is used. DMA is default.
38
39 If unsure, choose this option.
40
41config BCM43XX_DMA_MODE
42 bool "DMA (Direct Memory Access) only"
43 select BCM43XX_DMA
44 ---help---
45 Only include Direct Memory Access (DMA).
46 This reduces the size of the driver module, by omitting the PIO code.
47
48config BCM43XX_PIO_MODE
49 bool "PIO (Programmed I/O) only"
50 select BCM43XX_PIO
51 ---help---
52 Only include Programmed I/O (PIO).
53 This reduces the size of the driver module, by omitting the DMA code.
54 Please note that PIO transfers are slow (compared to DMA).
55
56 Also note that not all devices of the 43xx series support PIO.
57 The 4306 (Apple Airport Extreme and others) supports PIO, while
58 the 4318 is known to _not_ support PIO.
59
60 Only use PIO, if DMA does not work for you.
61
62endchoice
diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile
new file mode 100644
index 000000000000..bb5220c629d2
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/Makefile
@@ -0,0 +1,12 @@
1obj-$(CONFIG_BCM43XX) += bcm43xx.o
2bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o
3
4bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o
5bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o
6
7bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \
8 bcm43xx_radio.o bcm43xx_phy.o \
9 bcm43xx_power.o bcm43xx_wx.o \
10 bcm43xx_leds.o bcm43xx_ethtool.o \
11 bcm43xx_xmit.o bcm43xx_sysfs.o \
12 $(bcm43xx-obj-y)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
new file mode 100644
index 000000000000..dcadd295de4f
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -0,0 +1,926 @@
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#include "bcm43xx_sysfs.h"
19
20
21#define PFX KBUILD_MODNAME ": "
22
23#define BCM43xx_SWITCH_CORE_MAX_RETRIES 50
24#define BCM43xx_IRQWAIT_MAX_RETRIES 50
25
26#define BCM43xx_IO_SIZE 8192
27
28/* Active Core PCI Configuration Register. */
29#define BCM43xx_PCICFG_ACTIVE_CORE 0x80
30/* SPROM control register. */
31#define BCM43xx_PCICFG_SPROMCTL 0x88
32/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */
33#define BCM43xx_PCICFG_ICR 0x94
34
35/* MMIO offsets */
36#define BCM43xx_MMIO_DMA1_REASON 0x20
37#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24
38#define BCM43xx_MMIO_DMA2_REASON 0x28
39#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C
40#define BCM43xx_MMIO_DMA3_REASON 0x30
41#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34
42#define BCM43xx_MMIO_DMA4_REASON 0x38
43#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C
44#define BCM43xx_MMIO_STATUS_BITFIELD 0x120
45#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124
46#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128
47#define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C
48#define BCM43xx_MMIO_RAM_CONTROL 0x130
49#define BCM43xx_MMIO_RAM_DATA 0x134
50#define BCM43xx_MMIO_PS_STATUS 0x140
51#define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158
52#define BCM43xx_MMIO_SHM_CONTROL 0x160
53#define BCM43xx_MMIO_SHM_DATA 0x164
54#define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166
55#define BCM43xx_MMIO_XMITSTAT_0 0x170
56#define BCM43xx_MMIO_XMITSTAT_1 0x174
57#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
58#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
59#define BCM43xx_MMIO_DMA1_BASE 0x200
60#define BCM43xx_MMIO_DMA2_BASE 0x220
61#define BCM43xx_MMIO_DMA3_BASE 0x240
62#define BCM43xx_MMIO_DMA4_BASE 0x260
63#define BCM43xx_MMIO_PIO1_BASE 0x300
64#define BCM43xx_MMIO_PIO2_BASE 0x310
65#define BCM43xx_MMIO_PIO3_BASE 0x320
66#define BCM43xx_MMIO_PIO4_BASE 0x330
67#define BCM43xx_MMIO_PHY_VER 0x3E0
68#define BCM43xx_MMIO_PHY_RADIO 0x3E2
69#define BCM43xx_MMIO_ANTENNA 0x3E8
70#define BCM43xx_MMIO_CHANNEL 0x3F0
71#define BCM43xx_MMIO_CHANNEL_EXT 0x3F4
72#define BCM43xx_MMIO_RADIO_CONTROL 0x3F6
73#define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8
74#define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA
75#define BCM43xx_MMIO_PHY_CONTROL 0x3FC
76#define BCM43xx_MMIO_PHY_DATA 0x3FE
77#define BCM43xx_MMIO_MACFILTER_CONTROL 0x420
78#define BCM43xx_MMIO_MACFILTER_DATA 0x422
79#define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A
80#define BCM43xx_MMIO_GPIO_CONTROL 0x49C
81#define BCM43xx_MMIO_GPIO_MASK 0x49E
82#define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */
83#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */
84#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */
85#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */
86#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8
87
88/* SPROM offsets. */
89#define BCM43xx_SPROM_BASE 0x1000
90#define BCM43xx_SPROM_BOARDFLAGS2 0x1c
91#define BCM43xx_SPROM_IL0MACADDR 0x24
92#define BCM43xx_SPROM_ET0MACADDR 0x27
93#define BCM43xx_SPROM_ET1MACADDR 0x2a
94#define BCM43xx_SPROM_ETHPHY 0x2d
95#define BCM43xx_SPROM_BOARDREV 0x2e
96#define BCM43xx_SPROM_PA0B0 0x2f
97#define BCM43xx_SPROM_PA0B1 0x30
98#define BCM43xx_SPROM_PA0B2 0x31
99#define BCM43xx_SPROM_WL0GPIO0 0x32
100#define BCM43xx_SPROM_WL0GPIO2 0x33
101#define BCM43xx_SPROM_MAXPWR 0x34
102#define BCM43xx_SPROM_PA1B0 0x35
103#define BCM43xx_SPROM_PA1B1 0x36
104#define BCM43xx_SPROM_PA1B2 0x37
105#define BCM43xx_SPROM_IDL_TSSI_TGT 0x38
106#define BCM43xx_SPROM_BOARDFLAGS 0x39
107#define BCM43xx_SPROM_ANTENNA_GAIN 0x3a
108#define BCM43xx_SPROM_VERSION 0x3f
109
110/* BCM43xx_SPROM_BOARDFLAGS values */
111#define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
112#define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
113#define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */
114#define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */
115#define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */
116#define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */
117#define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */
118#define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */
119#define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */
120#define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */
121#define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */
122#define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */
123#define BCM43xx_BFL_EXTLNA 0x1000 /* has an external LNA */
124#define BCM43xx_BFL_HGPA 0x2000 /* had high gain PA */
125#define BCM43xx_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
126#define BCM43xx_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
127
128/* GPIO register offset, in both ChipCommon and PCI core. */
129#define BCM43xx_GPIO_CONTROL 0x6c
130
131/* SHM Routing */
132#define BCM43xx_SHM_SHARED 0x0001
133#define BCM43xx_SHM_WIRELESS 0x0002
134#define BCM43xx_SHM_PCM 0x0003
135#define BCM43xx_SHM_HWMAC 0x0004
136#define BCM43xx_SHM_UCODE 0x0300
137
138/* MacFilter offsets. */
139#define BCM43xx_MACFILTER_SELF 0x0000
140#define BCM43xx_MACFILTER_ASSOC 0x0003
141
142/* Chipcommon registers. */
143#define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04
144#define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0
145#define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4
146#define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8
147#define BCM43xx_CHIPCOMMON_SYSCLKCTL 0xC0
148
149/* PCI core specific registers. */
150#define BCM43xx_PCICORE_BCAST_ADDR 0x50
151#define BCM43xx_PCICORE_BCAST_DATA 0x54
152#define BCM43xx_PCICORE_SBTOPCI2 0x108
153
154/* SBTOPCI2 values. */
155#define BCM43xx_SBTOPCI2_PREFETCH 0x4
156#define BCM43xx_SBTOPCI2_BURST 0x8
157
158/* Chipcommon capabilities. */
159#define BCM43xx_CAPABILITIES_PCTL 0x00040000
160#define BCM43xx_CAPABILITIES_PLLMASK 0x00030000
161#define BCM43xx_CAPABILITIES_PLLSHIFT 16
162#define BCM43xx_CAPABILITIES_FLASHMASK 0x00000700
163#define BCM43xx_CAPABILITIES_FLASHSHIFT 8
164#define BCM43xx_CAPABILITIES_EXTBUSPRESENT 0x00000040
165#define BCM43xx_CAPABILITIES_UARTGPIO 0x00000020
166#define BCM43xx_CAPABILITIES_UARTCLOCKMASK 0x00000018
167#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT 3
168#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN 0x00000004
169#define BCM43xx_CAPABILITIES_NRUARTSMASK 0x00000003
170
171/* PowerControl */
172#define BCM43xx_PCTL_IN 0xB0
173#define BCM43xx_PCTL_OUT 0xB4
174#define BCM43xx_PCTL_OUTENABLE 0xB8
175#define BCM43xx_PCTL_XTAL_POWERUP 0x40
176#define BCM43xx_PCTL_PLL_POWERDOWN 0x80
177
178/* PowerControl Clock Modes */
179#define BCM43xx_PCTL_CLK_FAST 0x00
180#define BCM43xx_PCTL_CLK_SLOW 0x01
181#define BCM43xx_PCTL_CLK_DYNAMIC 0x02
182
183#define BCM43xx_PCTL_FORCE_SLOW 0x0800
184#define BCM43xx_PCTL_FORCE_PLL 0x1000
185#define BCM43xx_PCTL_DYN_XTAL 0x2000
186
187/* COREIDs */
188#define BCM43xx_COREID_CHIPCOMMON 0x800
189#define BCM43xx_COREID_ILINE20 0x801
190#define BCM43xx_COREID_SDRAM 0x803
191#define BCM43xx_COREID_PCI 0x804
192#define BCM43xx_COREID_MIPS 0x805
193#define BCM43xx_COREID_ETHERNET 0x806
194#define BCM43xx_COREID_V90 0x807
195#define BCM43xx_COREID_USB11_HOSTDEV 0x80a
196#define BCM43xx_COREID_IPSEC 0x80b
197#define BCM43xx_COREID_PCMCIA 0x80d
198#define BCM43xx_COREID_EXT_IF 0x80f
199#define BCM43xx_COREID_80211 0x812
200#define BCM43xx_COREID_MIPS_3302 0x816
201#define BCM43xx_COREID_USB11_HOST 0x817
202#define BCM43xx_COREID_USB11_DEV 0x818
203#define BCM43xx_COREID_USB20_HOST 0x819
204#define BCM43xx_COREID_USB20_DEV 0x81a
205#define BCM43xx_COREID_SDIO_HOST 0x81b
206
207/* Core Information Registers */
208#define BCM43xx_CIR_BASE 0xf00
209#define BCM43xx_CIR_SBTPSFLAG (BCM43xx_CIR_BASE + 0x18)
210#define BCM43xx_CIR_SBIMSTATE (BCM43xx_CIR_BASE + 0x90)
211#define BCM43xx_CIR_SBINTVEC (BCM43xx_CIR_BASE + 0x94)
212#define BCM43xx_CIR_SBTMSTATELOW (BCM43xx_CIR_BASE + 0x98)
213#define BCM43xx_CIR_SBTMSTATEHIGH (BCM43xx_CIR_BASE + 0x9c)
214#define BCM43xx_CIR_SBIMCONFIGLOW (BCM43xx_CIR_BASE + 0xa8)
215#define BCM43xx_CIR_SB_ID_HI (BCM43xx_CIR_BASE + 0xfc)
216
217/* Mask to get the Backplane Flag Number from SBTPSFLAG. */
218#define BCM43xx_BACKPLANE_FLAG_NR_MASK 0x3f
219
220/* SBIMCONFIGLOW values/masks. */
221#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK 0x00000007
222#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT 0
223#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK 0x00000070
224#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT 4
225#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK 0x00ff0000
226#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT 16
227
228/* sbtmstatelow state flags */
229#define BCM43xx_SBTMSTATELOW_RESET 0x01
230#define BCM43xx_SBTMSTATELOW_REJECT 0x02
231#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000
232#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000
233
234/* sbtmstatehigh state flags */
235#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1
236#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4
237
238/* sbimstate flags */
239#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000
240#define BCM43xx_SBIMSTATE_TIMEOUT 0x40000
241
242/* PHYVersioning */
243#define BCM43xx_PHYTYPE_A 0x00
244#define BCM43xx_PHYTYPE_B 0x01
245#define BCM43xx_PHYTYPE_G 0x02
246
247/* PHYRegisters */
248#define BCM43xx_PHY_ILT_A_CTRL 0x0072
249#define BCM43xx_PHY_ILT_A_DATA1 0x0073
250#define BCM43xx_PHY_ILT_A_DATA2 0x0074
251#define BCM43xx_PHY_G_LO_CONTROL 0x0810
252#define BCM43xx_PHY_ILT_G_CTRL 0x0472
253#define BCM43xx_PHY_ILT_G_DATA1 0x0473
254#define BCM43xx_PHY_ILT_G_DATA2 0x0474
255#define BCM43xx_PHY_A_PCTL 0x007B
256#define BCM43xx_PHY_G_PCTL 0x0029
257#define BCM43xx_PHY_A_CRS 0x0029
258#define BCM43xx_PHY_RADIO_BITFIELD 0x0401
259#define BCM43xx_PHY_G_CRS 0x0429
260#define BCM43xx_PHY_NRSSILT_CTRL 0x0803
261#define BCM43xx_PHY_NRSSILT_DATA 0x0804
262
263/* RadioRegisters */
264#define BCM43xx_RADIOCTL_ID 0x01
265
266/* StatusBitField */
267#define BCM43xx_SBF_MAC_ENABLED 0x00000001
268#define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/
269#define BCM43xx_SBF_CORE_READY 0x00000004
270#define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/
271#define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/
272#define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/
273#define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000
274#define BCM43xx_SBF_MODE_NOTADHOC 0x00020000
275#define BCM43xx_SBF_MODE_AP 0x00040000
276#define BCM43xx_SBF_RADIOREG_LOCK 0x00080000
277#define BCM43xx_SBF_MODE_MONITOR 0x00400000
278#define BCM43xx_SBF_MODE_PROMISC 0x01000000
279#define BCM43xx_SBF_PS1 0x02000000
280#define BCM43xx_SBF_PS2 0x04000000
281#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000
282#define BCM43xx_SBF_TIME_UPDATE 0x10000000
283#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/
284
285/* MicrocodeFlagsBitfield (addr + lo-word values?)*/
286#define BCM43xx_UCODEFLAGS_OFFSET 0x005E
287
288#define BCM43xx_UCODEFLAG_AUTODIV 0x0001
289#define BCM43xx_UCODEFLAG_UNKBGPHY 0x0002
290#define BCM43xx_UCODEFLAG_UNKBPHY 0x0004
291#define BCM43xx_UCODEFLAG_UNKGPHY 0x0020
292#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040
293#define BCM43xx_UCODEFLAG_JAPAN 0x0080
294
295/* Generic-Interrupt reasons. */
296#define BCM43xx_IRQ_READY (1 << 0)
297#define BCM43xx_IRQ_BEACON (1 << 1)
298#define BCM43xx_IRQ_PS (1 << 2)
299#define BCM43xx_IRQ_REG124 (1 << 5)
300#define BCM43xx_IRQ_PMQ (1 << 6)
301#define BCM43xx_IRQ_PIO_WORKAROUND (1 << 8)
302#define BCM43xx_IRQ_XMIT_ERROR (1 << 11)
303#define BCM43xx_IRQ_RX (1 << 15)
304#define BCM43xx_IRQ_SCAN (1 << 16)
305#define BCM43xx_IRQ_NOISE (1 << 18)
306#define BCM43xx_IRQ_XMIT_STATUS (1 << 29)
307
308#define BCM43xx_IRQ_ALL 0xffffffff
309#define BCM43xx_IRQ_INITIAL (BCM43xx_IRQ_PS | \
310 BCM43xx_IRQ_REG124 | \
311 BCM43xx_IRQ_PMQ | \
312 BCM43xx_IRQ_XMIT_ERROR | \
313 BCM43xx_IRQ_RX | \
314 BCM43xx_IRQ_SCAN | \
315 BCM43xx_IRQ_NOISE | \
316 BCM43xx_IRQ_XMIT_STATUS)
317
318
319/* Initial default iw_mode */
320#define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA
321
322/* Bus type PCI. */
323#define BCM43xx_BUSTYPE_PCI 0
324/* Bus type Silicone Backplane Bus. */
325#define BCM43xx_BUSTYPE_SB 1
326/* Bus type PCMCIA. */
327#define BCM43xx_BUSTYPE_PCMCIA 2
328
329/* Threshold values. */
330#define BCM43xx_MIN_RTS_THRESHOLD 1U
331#define BCM43xx_MAX_RTS_THRESHOLD 2304U
332#define BCM43xx_DEFAULT_RTS_THRESHOLD BCM43xx_MAX_RTS_THRESHOLD
333
334#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7
335#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4
336
337/* Max size of a security key */
338#define BCM43xx_SEC_KEYSIZE 16
339/* Security algorithms. */
340enum {
341 BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
342 BCM43xx_SEC_ALGO_WEP,
343 BCM43xx_SEC_ALGO_UNKNOWN,
344 BCM43xx_SEC_ALGO_AES,
345 BCM43xx_SEC_ALGO_WEP104,
346 BCM43xx_SEC_ALGO_TKIP,
347};
348
349#ifdef assert
350# undef assert
351#endif
352#ifdef CONFIG_BCM43XX_DEBUG
353#define assert(expr) \
354 do { \
355 if (unlikely(!(expr))) { \
356 printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \
357 #expr, __FILE__, __LINE__, __FUNCTION__); \
358 } \
359 } while (0)
360#else
361#define assert(expr) do { /* nothing */ } while (0)
362#endif
363
364/* rate limited printk(). */
365#ifdef printkl
366# undef printkl
367#endif
368#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
369/* rate limited printk() for debugging */
370#ifdef dprintkl
371# undef dprintkl
372#endif
373#ifdef CONFIG_BCM43XX_DEBUG
374# define dprintkl printkl
375#else
376# define dprintkl(f, x...) do { /* nothing */ } while (0)
377#endif
378
379/* Helper macro for if branches.
380 * An if branch marked with this macro is only taken in DEBUG mode.
381 * Example:
382 * if (DEBUG_ONLY(foo == bar)) {
383 * do something
384 * }
385 * In DEBUG mode, the branch will be taken if (foo == bar).
386 * In non-DEBUG mode, the branch will never be taken.
387 */
388#ifdef DEBUG_ONLY
389# undef DEBUG_ONLY
390#endif
391#ifdef CONFIG_BCM43XX_DEBUG
392# define DEBUG_ONLY(x) (x)
393#else
394# define DEBUG_ONLY(x) 0
395#endif
396
397/* debugging printk() */
398#ifdef dprintk
399# undef dprintk
400#endif
401#ifdef CONFIG_BCM43XX_DEBUG
402# define dprintk(f, x...) do { printk(f ,##x); } while (0)
403#else
404# define dprintk(f, x...) do { /* nothing */ } while (0)
405#endif
406
407
408struct net_device;
409struct pci_dev;
410struct bcm43xx_dmaring;
411struct bcm43xx_pioqueue;
412
413struct bcm43xx_initval {
414 u16 offset;
415 u16 size;
416 u32 value;
417} __attribute__((__packed__));
418
419/* Values for bcm430x_sprominfo.locale */
420enum {
421 BCM43xx_LOCALE_WORLD = 0,
422 BCM43xx_LOCALE_THAILAND,
423 BCM43xx_LOCALE_ISRAEL,
424 BCM43xx_LOCALE_JORDAN,
425 BCM43xx_LOCALE_CHINA,
426 BCM43xx_LOCALE_JAPAN,
427 BCM43xx_LOCALE_USA_CANADA_ANZ,
428 BCM43xx_LOCALE_EUROPE,
429 BCM43xx_LOCALE_USA_LOW,
430 BCM43xx_LOCALE_JAPAN_HIGH,
431 BCM43xx_LOCALE_ALL,
432 BCM43xx_LOCALE_NONE,
433};
434
435#define BCM43xx_SPROM_SIZE 64 /* in 16-bit words. */
436struct bcm43xx_sprominfo {
437 u16 boardflags2;
438 u8 il0macaddr[6];
439 u8 et0macaddr[6];
440 u8 et1macaddr[6];
441 u8 et0phyaddr:5;
442 u8 et1phyaddr:5;
443 u8 et0mdcport:1;
444 u8 et1mdcport:1;
445 u8 boardrev;
446 u8 locale:4;
447 u8 antennas_aphy:2;
448 u8 antennas_bgphy:2;
449 u16 pa0b0;
450 u16 pa0b1;
451 u16 pa0b2;
452 u8 wl0gpio0;
453 u8 wl0gpio1;
454 u8 wl0gpio2;
455 u8 wl0gpio3;
456 u8 maxpower_aphy;
457 u8 maxpower_bgphy;
458 u16 pa1b0;
459 u16 pa1b1;
460 u16 pa1b2;
461 u8 idle_tssi_tgt_aphy;
462 u8 idle_tssi_tgt_bgphy;
463 u16 boardflags;
464 u16 antennagain_aphy;
465 u16 antennagain_bgphy;
466};
467
468/* Value pair to measure the LocalOscillator. */
469struct bcm43xx_lopair {
470 s8 low;
471 s8 high;
472 u8 used:1;
473};
474#define BCM43xx_LO_COUNT (14*4)
475
476struct bcm43xx_phyinfo {
477 /* Hardware Data */
478 u8 version;
479 u8 type;
480 u8 rev;
481 u16 antenna_diversity;
482 u16 savedpctlreg;
483 u16 minlowsig[2];
484 u16 minlowsigpos[2];
485 u8 connected:1,
486 calibrated:1,
487 is_locked:1, /* used in bcm43xx_phy_{un}lock() */
488 dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */
489 /* LO Measurement Data.
490 * Use bcm43xx_get_lopair() to get a value.
491 */
492 struct bcm43xx_lopair *_lo_pairs;
493
494 /* TSSI to dBm table in use */
495 const s8 *tssi2dbm;
496 /* idle TSSI value */
497 s8 idle_tssi;
498
499 /* Values from bcm43xx_calc_loopback_gain() */
500 u16 loopback_gain[2];
501
502 /* PHY lock for core.rev < 3
503 * This lock is only used by bcm43xx_phy_{un}lock()
504 */
505 spinlock_t lock;
506};
507
508
509struct bcm43xx_radioinfo {
510 u16 manufact;
511 u16 version;
512 u8 revision;
513
514 /* Desired TX power in dBm Q5.2 */
515 u16 txpower_desired;
516 /* TX Power control values. */
517 union {
518 /* B/G PHY */
519 struct {
520 u16 baseband_atten;
521 u16 radio_atten;
522 u16 txctl1;
523 u16 txctl2;
524 };
525 /* A PHY */
526 struct {
527 u16 txpwr_offset;
528 };
529 };
530
531 /* Current Interference Mitigation mode */
532 int interfmode;
533 /* Stack of saved values from the Interference Mitigation code.
534 * Each value in the stack is layed out as follows:
535 * bit 0-11: offset
536 * bit 12-15: register ID
537 * bit 16-32: value
538 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
539 */
540#define BCM43xx_INTERFSTACK_SIZE 26
541 u32 interfstack[BCM43xx_INTERFSTACK_SIZE];
542
543 /* Saved values from the NRSSI Slope calculation */
544 s16 nrssi[2];
545 s32 nrssislope;
546 /* In memory nrssi lookup table. */
547 s8 nrssi_lt[64];
548
549 /* current channel */
550 u8 channel;
551 u8 initial_channel;
552
553 u16 lofcal;
554
555 u16 initval;
556
557 u8 enabled:1;
558 /* ACI (adjacent channel interference) flags. */
559 u8 aci_enable:1,
560 aci_wlan_automatic:1,
561 aci_hw_rssi:1;
562};
563
564/* Data structures for DMA transmission, per 80211 core. */
565struct bcm43xx_dma {
566 struct bcm43xx_dmaring *tx_ring0;
567 struct bcm43xx_dmaring *tx_ring1;
568 struct bcm43xx_dmaring *tx_ring2;
569 struct bcm43xx_dmaring *tx_ring3;
570 struct bcm43xx_dmaring *rx_ring0;
571 struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
572};
573
574/* Data structures for PIO transmission, per 80211 core. */
575struct bcm43xx_pio {
576 struct bcm43xx_pioqueue *queue0;
577 struct bcm43xx_pioqueue *queue1;
578 struct bcm43xx_pioqueue *queue2;
579 struct bcm43xx_pioqueue *queue3;
580};
581
582#define BCM43xx_MAX_80211_CORES 2
583
584#ifdef CONFIG_BCM947XX
585#define core_offset(bcm) (bcm)->current_core_offset
586#else
587#define core_offset(bcm) 0
588#endif
589
590/* Generic information about a core. */
591struct bcm43xx_coreinfo {
592 u8 available:1,
593 enabled:1,
594 initialized:1;
595 /** core_id ID number */
596 u16 id;
597 /** core_rev revision number */
598 u8 rev;
599 /** Index number for _switch_core() */
600 u8 index;
601};
602
603/* Additional information for each 80211 core. */
604struct bcm43xx_coreinfo_80211 {
605 /* PHY device. */
606 struct bcm43xx_phyinfo phy;
607 /* Radio device. */
608 struct bcm43xx_radioinfo radio;
609 union {
610 /* DMA context. */
611 struct bcm43xx_dma dma;
612 /* PIO context. */
613 struct bcm43xx_pio pio;
614 };
615};
616
617/* Context information for a noise calculation (Link Quality). */
618struct bcm43xx_noise_calculation {
619 struct bcm43xx_coreinfo *core_at_start;
620 u8 channel_at_start;
621 u8 calculation_running:1;
622 u8 nr_samples;
623 s8 samples[8][4];
624};
625
626struct bcm43xx_stats {
627 u8 link_quality;
628 u8 noise;
629 struct iw_statistics wstats;
630 /* Store the last TX/RX times here for updating the leds. */
631 unsigned long last_tx;
632 unsigned long last_rx;
633};
634
635struct bcm43xx_key {
636 u8 enabled:1;
637 u8 algorithm;
638};
639
640struct bcm43xx_private {
641 struct bcm43xx_sysfs sysfs;
642
643 struct ieee80211_device *ieee;
644 struct ieee80211softmac_device *softmac;
645
646 struct net_device *net_dev;
647 struct pci_dev *pci_dev;
648 unsigned int irq;
649
650 void __iomem *mmio_addr;
651 unsigned int mmio_len;
652
653 /* Do not use the lock directly. Use the bcm43xx_lock* helper
654 * functions, to be MMIO-safe. */
655 spinlock_t _lock;
656
657 /* Driver status flags. */
658 u32 initialized:1, /* init_board() succeed */
659 was_initialized:1, /* for PCI suspend/resume. */
660 shutting_down:1, /* free_board() in progress */
661 __using_pio:1, /* Internal, use bcm43xx_using_pio(). */
662 bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
663 reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
664 powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */
665 short_preamble:1, /* TRUE, if short preamble is enabled. */
666 firmware_norelease:1; /* Do not release the firmware. Used on suspend. */
667
668 struct bcm43xx_stats stats;
669
670 /* Bus type we are connected to.
671 * This is currently always BCM43xx_BUSTYPE_PCI
672 */
673 u8 bustype;
674
675 u16 board_vendor;
676 u16 board_type;
677 u16 board_revision;
678
679 u16 chip_id;
680 u8 chip_rev;
681 u8 chip_package;
682
683 struct bcm43xx_sprominfo sprom;
684#define BCM43xx_NR_LEDS 4
685 struct bcm43xx_led leds[BCM43xx_NR_LEDS];
686
687 /* The currently active core. */
688 struct bcm43xx_coreinfo *current_core;
689#ifdef CONFIG_BCM947XX
690 /** current core memory offset */
691 u32 current_core_offset;
692#endif
693 struct bcm43xx_coreinfo *active_80211_core;
694 /* coreinfo structs for all possible cores follow.
695 * Note that a core might not exist.
696 * So check the coreinfo flags before using it.
697 */
698 struct bcm43xx_coreinfo core_chipcommon;
699 struct bcm43xx_coreinfo core_pci;
700 struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
701 /* Additional information, specific to the 80211 cores. */
702 struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
703 /* Index of the current 80211 core. If current_core is not
704 * an 80211 core, this is -1.
705 */
706 int current_80211_core_idx;
707 /* Number of available 80211 cores. */
708 int nr_80211_available;
709
710 u32 chipcommon_capabilities;
711
712 /* Reason code of the last interrupt. */
713 u32 irq_reason;
714 u32 dma_reason[4];
715 /* saved irq enable/disable state bitfield. */
716 u32 irq_savedstate;
717 /* Link Quality calculation context. */
718 struct bcm43xx_noise_calculation noisecalc;
719
720 /* Threshold values. */
721 //TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
722 u32 rts_threshold;
723
724 /* Interrupt Service Routine tasklet (bottom-half) */
725 struct tasklet_struct isr_tasklet;
726
727 /* Periodic tasks */
728 struct timer_list periodic_tasks;
729 unsigned int periodic_state;
730
731 struct work_struct restart_work;
732
733 /* Informational stuff. */
734 char nick[IW_ESSID_MAX_SIZE + 1];
735
736 /* encryption/decryption */
737 u16 security_offset;
738 struct bcm43xx_key key[54];
739 u8 default_key_idx;
740
741 /* Firmware. */
742 const struct firmware *ucode;
743 const struct firmware *pcm;
744 const struct firmware *initvals0;
745 const struct firmware *initvals1;
746
747 /* Debugging stuff follows. */
748#ifdef CONFIG_BCM43XX_DEBUG
749 struct bcm43xx_dfsentry *dfsentry;
750#endif
751};
752
753/* bcm43xx_(un)lock() protect struct bcm43xx_private.
754 * Note that _NO_ MMIO writes are allowed. If you want to
755 * write to the device through MMIO in the critical section, use
756 * the *_mmio lock functions.
757 * MMIO read-access is allowed, though.
758 */
759#define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags)
760#define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags)
761/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
762 * MMIO write-access to the device is allowed.
763 * All MMIO writes are flushed on unlock, so it is guaranteed to not
764 * interfere with other threads writing MMIO registers.
765 */
766#define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags)
767#define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)
768
769static inline
770struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
771{
772 return ieee80211softmac_priv(dev);
773}
774
775
776/* Helper function, which returns a boolean.
777 * TRUE, if PIO is used; FALSE, if DMA is used.
778 */
779#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
780static inline
781int bcm43xx_using_pio(struct bcm43xx_private *bcm)
782{
783 return bcm->__using_pio;
784}
785#elif defined(CONFIG_BCM43XX_DMA)
786static inline
787int bcm43xx_using_pio(struct bcm43xx_private *bcm)
788{
789 return 0;
790}
791#elif defined(CONFIG_BCM43XX_PIO)
792static inline
793int bcm43xx_using_pio(struct bcm43xx_private *bcm)
794{
795 return 1;
796}
797#else
798# error "Using neither DMA nor PIO? Confused..."
799#endif
800
801/* Helper functions to access data structures private to the 80211 cores.
802 * Note that we _must_ have an 80211 core mapped when calling
803 * any of these functions.
804 */
805static inline
806struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
807{
808 assert(bcm43xx_using_pio(bcm));
809 assert(bcm->current_80211_core_idx >= 0);
810 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
811 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
812}
813static inline
814struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
815{
816 assert(!bcm43xx_using_pio(bcm));
817 assert(bcm->current_80211_core_idx >= 0);
818 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
819 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
820}
821static inline
822struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
823{
824 assert(bcm->current_80211_core_idx >= 0);
825 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
826 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
827}
828static inline
829struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
830{
831 assert(bcm->current_80211_core_idx >= 0);
832 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
833 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
834}
835
836/* Are we running in init_board() context? */
837static inline
838int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
839{
840 if (bcm->initialized)
841 return 0;
842 if (bcm->shutting_down)
843 return 0;
844 return 1;
845}
846
847static inline
848struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
849 u16 radio_attenuation,
850 u16 baseband_attenuation)
851{
852 return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2));
853}
854
855
856static inline
857u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
858{
859 return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
860}
861
862static inline
863void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
864{
865 iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
866}
867
868static inline
869u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
870{
871 return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
872}
873
874static inline
875void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
876{
877 iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
878}
879
880static inline
881int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value)
882{
883 return pci_read_config_word(bcm->pci_dev, offset, value);
884}
885
886static inline
887int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value)
888{
889 return pci_read_config_dword(bcm->pci_dev, offset, value);
890}
891
892static inline
893int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value)
894{
895 return pci_write_config_word(bcm->pci_dev, offset, value);
896}
897
898static inline
899int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value)
900{
901 return pci_write_config_dword(bcm->pci_dev, offset, value);
902}
903
904/** Limit a value between two limits */
905#ifdef limit_value
906# undef limit_value
907#endif
908#define limit_value(value, min, max) \
909 ({ \
910 typeof(value) __value = (value); \
911 typeof(value) __min = (min); \
912 typeof(value) __max = (max); \
913 if (__value < __min) \
914 __value = __min; \
915 else if (__value > __max) \
916 __value = __max; \
917 __value; \
918 })
919
920/** Helpers to print MAC addresses. */
921#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x"
922#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \
923 ((u8*)(x))[2], ((u8*)(x))[3], \
924 ((u8*)(x))[4], ((u8*)(x))[5]
925
926#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..d2c3401e9b70
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -0,0 +1,499 @@
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#include "bcm43xx_xmit.h"
41
42#define REALLY_BIG_BUFFER_SIZE (1024*256)
43
44static struct bcm43xx_debugfs fs;
45static char really_big_buffer[REALLY_BIG_BUFFER_SIZE];
46static DECLARE_MUTEX(big_buffer_sem);
47
48
49static ssize_t write_file_dummy(struct file *file, const char __user *buf,
50 size_t count, loff_t *ppos)
51{
52 return count;
53}
54
55static int open_file_generic(struct inode *inode, struct file *file)
56{
57 file->private_data = inode->u.generic_ip;
58 return 0;
59}
60
61#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x)
62
63static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
64 size_t count, loff_t *ppos)
65{
66 const size_t len = REALLY_BIG_BUFFER_SIZE;
67
68 struct bcm43xx_private *bcm = file->private_data;
69 char *buf = really_big_buffer;
70 size_t pos = 0;
71 ssize_t res;
72 struct net_device *net_dev;
73 struct pci_dev *pci_dev;
74 unsigned long flags;
75 u16 tmp16;
76 int i;
77
78 down(&big_buffer_sem);
79
80 bcm43xx_lock_mmio(bcm, flags);
81 if (!bcm->initialized) {
82 fappend("Board not initialized.\n");
83 goto out;
84 }
85 net_dev = bcm->net_dev;
86 pci_dev = bcm->pci_dev;
87
88 /* This is where the information is written to the "devinfo" file */
89 fappend("*** %s devinfo ***\n", net_dev->name);
90 fappend("vendor: 0x%04x device: 0x%04x\n",
91 pci_dev->vendor, pci_dev->device);
92 fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n",
93 pci_dev->subsystem_vendor, pci_dev->subsystem_device);
94 fappend("IRQ: %d\n", bcm->irq);
95 fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len);
96 fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
97 if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
98 fappend("Radio disabled by hardware!\n");
99 if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4)))
100 fappend("Radio disabled by hardware!\n");
101 fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor,
102 bcm->board_type);
103
104 fappend("\nCores:\n");
105#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \
106 "rev: 0x%02x, index: 0x%02x\n", \
107 (info).available \
108 ? "available" : "nonavailable", \
109 (info).enabled \
110 ? "enabled" : "disabled", \
111 (info).id, (info).rev, (info).index)
112 fappend_core("CHIPCOMMON", bcm->core_chipcommon);
113 fappend_core("PCI", bcm->core_pci);
114 fappend_core("first 80211", bcm->core_80211[0]);
115 fappend_core("second 80211", bcm->core_80211[1]);
116#undef fappend_core
117 tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
118 fappend("LEDs: ");
119 for (i = 0; i < BCM43xx_NR_LEDS; i++)
120 fappend("%d ", !!(tmp16 & (1 << i)));
121 fappend("\n");
122
123out:
124 bcm43xx_unlock_mmio(bcm, flags);
125 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
126 up(&big_buffer_sem);
127 return res;
128}
129
130static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf,
131 size_t count, loff_t *ppos)
132{
133 const size_t len = REALLY_BIG_BUFFER_SIZE;
134
135 char *buf = really_big_buffer;
136 size_t pos = 0;
137 ssize_t res;
138
139 down(&big_buffer_sem);
140
141 /* This is where the information is written to the "driver" file */
142 fappend(KBUILD_MODNAME " driver\n");
143 fappend("Compiled at: %s %s\n", __DATE__, __TIME__);
144
145 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
146 up(&big_buffer_sem);
147 return res;
148}
149
150static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
151 size_t count, loff_t *ppos)
152{
153 const size_t len = REALLY_BIG_BUFFER_SIZE;
154
155 struct bcm43xx_private *bcm = file->private_data;
156 char *buf = really_big_buffer;
157 size_t pos = 0;
158 ssize_t res;
159 unsigned long flags;
160
161 down(&big_buffer_sem);
162 bcm43xx_lock_mmio(bcm, flags);
163 if (!bcm->initialized) {
164 fappend("Board not initialized.\n");
165 goto out;
166 }
167
168 /* This is where the information is written to the "sprom_dump" file */
169 fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
170
171out:
172 bcm43xx_unlock_mmio(bcm, flags);
173 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
174 up(&big_buffer_sem);
175 return res;
176}
177
178static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
179 size_t count, loff_t *ppos)
180{
181 const size_t len = REALLY_BIG_BUFFER_SIZE;
182
183 struct bcm43xx_private *bcm = file->private_data;
184 char *buf = really_big_buffer;
185 size_t pos = 0;
186 ssize_t res;
187 unsigned long flags;
188 u64 tsf;
189
190 down(&big_buffer_sem);
191 bcm43xx_lock_mmio(bcm, flags);
192 if (!bcm->initialized) {
193 fappend("Board not initialized.\n");
194 goto out;
195 }
196 bcm43xx_tsf_read(bcm, &tsf);
197 fappend("0x%08x%08x\n",
198 (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
199 (unsigned int)(tsf & 0xFFFFFFFFULL));
200
201out:
202 bcm43xx_unlock_mmio(bcm, flags);
203 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
204 up(&big_buffer_sem);
205 return res;
206}
207
208static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
209 size_t count, loff_t *ppos)
210{
211 struct bcm43xx_private *bcm = file->private_data;
212 char *buf = really_big_buffer;
213 ssize_t buf_size;
214 ssize_t res;
215 unsigned long flags;
216 u64 tsf;
217
218 buf_size = min(count, sizeof (really_big_buffer) - 1);
219 down(&big_buffer_sem);
220 if (copy_from_user(buf, user_buf, buf_size)) {
221 res = -EFAULT;
222 goto out_up;
223 }
224 bcm43xx_lock_mmio(bcm, flags);
225 if (!bcm->initialized) {
226 printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
227 res = -EFAULT;
228 goto out_unlock;
229 }
230 if (sscanf(buf, "%lli", &tsf) != 1) {
231 printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n");
232 res = -EINVAL;
233 goto out_unlock;
234 }
235 bcm43xx_tsf_write(bcm, tsf);
236 res = buf_size;
237
238out_unlock:
239 bcm43xx_unlock_mmio(bcm, flags);
240out_up:
241 up(&big_buffer_sem);
242 return res;
243}
244
245static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
246 size_t count, loff_t *ppos)
247{
248 const size_t len = REALLY_BIG_BUFFER_SIZE;
249
250 struct bcm43xx_private *bcm = file->private_data;
251 char *buf = really_big_buffer;
252 size_t pos = 0;
253 ssize_t res;
254 unsigned long flags;
255 struct bcm43xx_dfsentry *e;
256 struct bcm43xx_xmitstatus *status;
257 int i, cnt, j = 0;
258
259 down(&big_buffer_sem);
260 bcm43xx_lock(bcm, flags);
261
262 fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
263 BCM43xx_NR_LOGGED_XMITSTATUS);
264 e = bcm->dfsentry;
265 if (e->xmitstatus_printing == 0) {
266 /* At the beginning, make a copy of all data to avoid
267 * concurrency, as this function is called multiple
268 * times for big logs. Without copying, the data might
269 * change between reads. This would result in total trash.
270 */
271 e->xmitstatus_printing = 1;
272 e->saved_xmitstatus_ptr = e->xmitstatus_ptr;
273 e->saved_xmitstatus_cnt = e->xmitstatus_cnt;
274 memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer,
275 BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer)));
276 }
277 i = e->saved_xmitstatus_ptr - 1;
278 if (i < 0)
279 i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
280 cnt = e->saved_xmitstatus_cnt;
281 while (cnt) {
282 status = e->xmitstatus_print_buffer + i;
283 fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, "
284 "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, "
285 "unk: 0x%04x\n", j,
286 status->cookie, status->flags,
287 status->cnt1, status->cnt2, status->seq,
288 status->unknown);
289 j++;
290 cnt--;
291 i--;
292 if (i < 0)
293 i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
294 }
295
296 bcm43xx_unlock(bcm, flags);
297 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
298 bcm43xx_lock(bcm, flags);
299 if (*ppos == pos) {
300 /* Done. Drop the copied data. */
301 e->xmitstatus_printing = 0;
302 }
303 bcm43xx_unlock(bcm, flags);
304 up(&big_buffer_sem);
305 return res;
306}
307
308#undef fappend
309
310
311static struct file_operations devinfo_fops = {
312 .read = devinfo_read_file,
313 .write = write_file_dummy,
314 .open = open_file_generic,
315};
316
317static struct file_operations spromdump_fops = {
318 .read = spromdump_read_file,
319 .write = write_file_dummy,
320 .open = open_file_generic,
321};
322
323static struct file_operations drvinfo_fops = {
324 .read = drvinfo_read_file,
325 .write = write_file_dummy,
326 .open = open_file_generic,
327};
328
329static struct file_operations tsf_fops = {
330 .read = tsf_read_file,
331 .write = tsf_write_file,
332 .open = open_file_generic,
333};
334
335static struct file_operations txstat_fops = {
336 .read = txstat_read_file,
337 .write = write_file_dummy,
338 .open = open_file_generic,
339};
340
341
342void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
343{
344 struct bcm43xx_dfsentry *e;
345 char devdir[IFNAMSIZ];
346
347 assert(bcm);
348 e = kzalloc(sizeof(*e), GFP_KERNEL);
349 if (!e) {
350 printk(KERN_ERR PFX "out of memory\n");
351 return;
352 }
353 e->bcm = bcm;
354 e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
355 * sizeof(*(e->xmitstatus_buffer)),
356 GFP_KERNEL);
357 if (!e->xmitstatus_buffer) {
358 printk(KERN_ERR PFX "out of memory\n");
359 kfree(e);
360 return;
361 }
362 e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
363 * sizeof(*(e->xmitstatus_buffer)),
364 GFP_KERNEL);
365 if (!e->xmitstatus_print_buffer) {
366 printk(KERN_ERR PFX "out of memory\n");
367 kfree(e);
368 return;
369 }
370
371
372 bcm->dfsentry = e;
373
374 strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir));
375 e->subdir = debugfs_create_dir(devdir, fs.root);
376 e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir,
377 bcm, &devinfo_fops);
378 if (!e->dentry_devinfo)
379 printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir);
380 e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir,
381 bcm, &spromdump_fops);
382 if (!e->dentry_spromdump)
383 printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir);
384 e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir,
385 bcm, &tsf_fops);
386 if (!e->dentry_tsf)
387 printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
388 e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
389 bcm, &txstat_fops);
390 if (!e->dentry_txstat)
391 printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
392}
393
394void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
395{
396 struct bcm43xx_dfsentry *e;
397
398 if (!bcm)
399 return;
400
401 e = bcm->dfsentry;
402 assert(e);
403 debugfs_remove(e->dentry_spromdump);
404 debugfs_remove(e->dentry_devinfo);
405 debugfs_remove(e->dentry_tsf);
406 debugfs_remove(e->dentry_txstat);
407 debugfs_remove(e->subdir);
408 kfree(e->xmitstatus_buffer);
409 kfree(e->xmitstatus_print_buffer);
410 kfree(e);
411}
412
413void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
414 struct bcm43xx_xmitstatus *status)
415{
416 struct bcm43xx_dfsentry *e;
417 struct bcm43xx_xmitstatus *savedstatus;
418
419 /* This is protected by bcm->_lock */
420 e = bcm->dfsentry;
421 assert(e);
422 savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr;
423 memcpy(savedstatus, status, sizeof(*status));
424 e->xmitstatus_ptr++;
425 if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS)
426 e->xmitstatus_ptr = 0;
427 if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS)
428 e->xmitstatus_cnt++;
429}
430
431void bcm43xx_debugfs_init(void)
432{
433 memset(&fs, 0, sizeof(fs));
434 fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
435 if (!fs.root)
436 printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n");
437 fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
438 if (!fs.dentry_driverinfo)
439 printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n");
440}
441
442void bcm43xx_debugfs_exit(void)
443{
444 debugfs_remove(fs.dentry_driverinfo);
445 debugfs_remove(fs.root);
446}
447
448void bcm43xx_printk_dump(const char *data,
449 size_t size,
450 const char *description)
451{
452 size_t i;
453 char c;
454
455 printk(KERN_INFO PFX "Data dump (%s, %u bytes):",
456 description, size);
457 for (i = 0; i < size; i++) {
458 c = data[i];
459 if (i % 8 == 0)
460 printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff);
461 else
462 printk("0x%02x, ", c & 0xff);
463 }
464 printk("\n");
465}
466
467void bcm43xx_printk_bitdump(const unsigned char *data,
468 size_t bytes, int msb_to_lsb,
469 const char *description)
470{
471 size_t i;
472 int j;
473 const unsigned char *d;
474
475 printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***",
476 description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
477 for (i = 0; i < bytes; i++) {
478 d = data + i;
479 if (i % 8 == 0)
480 printk("\n" KERN_INFO PFX "0x%08x: ", i);
481 if (msb_to_lsb) {
482 for (j = 7; j >= 0; j--) {
483 if (*d & (1 << j))
484 printk("1");
485 else
486 printk("0");
487 }
488 } else {
489 for (j = 0; j < 8; j++) {
490 if (*d & (1 << j))
491 printk("1");
492 else
493 printk("0");
494 }
495 }
496 printk(" ");
497 }
498 printk("\n");
499}
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..c3681b8f09b4
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -0,0 +1,968 @@
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#include "bcm43xx_xmit.h"
36
37#include <linux/dma-mapping.h>
38#include <linux/pci.h>
39#include <linux/delay.h>
40#include <linux/skbuff.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
172/* Unmap and free a descriptor buffer. */
173static inline
174void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
175 struct bcm43xx_dmadesc *desc,
176 struct bcm43xx_dmadesc_meta *meta,
177 int irq_context)
178{
179 assert(meta->skb);
180 if (irq_context)
181 dev_kfree_skb_irq(meta->skb);
182 else
183 dev_kfree_skb(meta->skb);
184 meta->skb = NULL;
185}
186
187static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
188{
189 struct device *dev = &(ring->bcm->pci_dev->dev);
190
191 ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
192 &(ring->dmabase), GFP_KERNEL);
193 if (!ring->vbase) {
194 printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
195 return -ENOMEM;
196 }
197 if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
198 printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G "
199 "(0x%08x, len: %lu)\n",
200 ring->dmabase, BCM43xx_DMA_RINGMEMSIZE);
201 dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
202 ring->vbase, ring->dmabase);
203 return -ENOMEM;
204 }
205 assert(!(ring->dmabase & 0x000003FF));
206 memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
207
208 return 0;
209}
210
211static void free_ringmemory(struct bcm43xx_dmaring *ring)
212{
213 struct device *dev = &(ring->bcm->pci_dev->dev);
214
215 dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
216 ring->vbase, ring->dmabase);
217}
218
219/* Reset the RX DMA channel */
220int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
221 u16 mmio_base)
222{
223 int i;
224 u32 value;
225
226 bcm43xx_write32(bcm,
227 mmio_base + BCM43xx_DMA_RX_CONTROL,
228 0x00000000);
229 for (i = 0; i < 1000; i++) {
230 value = bcm43xx_read32(bcm,
231 mmio_base + BCM43xx_DMA_RX_STATUS);
232 value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
233 if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
234 i = -1;
235 break;
236 }
237 udelay(10);
238 }
239 if (i != -1) {
240 printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n");
241 return -ENODEV;
242 }
243
244 return 0;
245}
246
247/* Reset the RX DMA channel */
248int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
249 u16 mmio_base)
250{
251 int i;
252 u32 value;
253
254 for (i = 0; i < 1000; i++) {
255 value = bcm43xx_read32(bcm,
256 mmio_base + BCM43xx_DMA_TX_STATUS);
257 value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
258 if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
259 value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
260 value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
261 break;
262 udelay(10);
263 }
264 bcm43xx_write32(bcm,
265 mmio_base + BCM43xx_DMA_TX_CONTROL,
266 0x00000000);
267 for (i = 0; i < 1000; i++) {
268 value = bcm43xx_read32(bcm,
269 mmio_base + BCM43xx_DMA_TX_STATUS);
270 value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
271 if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
272 i = -1;
273 break;
274 }
275 udelay(10);
276 }
277 if (i != -1) {
278 printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n");
279 return -ENODEV;
280 }
281 /* ensure the reset is completed. */
282 udelay(300);
283
284 return 0;
285}
286
287static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
288 struct bcm43xx_dmadesc *desc,
289 struct bcm43xx_dmadesc_meta *meta,
290 gfp_t gfp_flags)
291{
292 struct bcm43xx_rxhdr *rxhdr;
293 dma_addr_t dmaaddr;
294 u32 desc_addr;
295 u32 desc_ctl;
296 const int slot = (int)(desc - ring->vbase);
297 struct sk_buff *skb;
298
299 assert(slot >= 0 && slot < ring->nr_slots);
300 assert(!ring->tx);
301
302 skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
303 if (unlikely(!skb))
304 return -ENOMEM;
305 dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
306 if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
307 unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
308 dev_kfree_skb_any(skb);
309 printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G "
310 "(0x%08x, len: %u)\n",
311 dmaaddr, ring->rx_buffersize);
312 return -ENOMEM;
313 }
314 meta->skb = skb;
315 meta->dmaaddr = dmaaddr;
316 skb->dev = ring->bcm->net_dev;
317 desc_addr = (u32)(dmaaddr + ring->memoffset);
318 desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
319 (u32)(ring->rx_buffersize - ring->frameoffset));
320 if (slot == ring->nr_slots - 1)
321 desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
322 set_desc_addr(desc, desc_addr);
323 set_desc_ctl(desc, desc_ctl);
324
325 rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
326 rxhdr->frame_length = 0;
327 rxhdr->flags1 = 0;
328
329 return 0;
330}
331
332/* Allocate the initial descbuffers.
333 * This is used for an RX ring only.
334 */
335static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
336{
337 int i, err = -ENOMEM;
338 struct bcm43xx_dmadesc *desc;
339 struct bcm43xx_dmadesc_meta *meta;
340
341 for (i = 0; i < ring->nr_slots; i++) {
342 desc = ring->vbase + i;
343 meta = ring->meta + i;
344
345 err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
346 if (err)
347 goto err_unwind;
348 }
349 ring->used_slots = ring->nr_slots;
350 err = 0;
351out:
352 return err;
353
354err_unwind:
355 for (i--; i >= 0; i--) {
356 desc = ring->vbase + i;
357 meta = ring->meta + i;
358
359 unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
360 dev_kfree_skb(meta->skb);
361 }
362 goto out;
363}
364
365/* Do initial setup of the DMA controller.
366 * Reset the controller, write the ring busaddress
367 * and switch the "enable" bit on.
368 */
369static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
370{
371 int err = 0;
372 u32 value;
373
374 if (ring->tx) {
375 /* Set Transmit Control register to "transmit enable" */
376 bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
377 BCM43xx_DMA_TXCTRL_ENABLE);
378 /* Set Transmit Descriptor ring address. */
379 bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING,
380 ring->dmabase + ring->memoffset);
381 } else {
382 err = alloc_initial_descbuffers(ring);
383 if (err)
384 goto out;
385 /* Set Receive Control "receive enable" and frame offset */
386 value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
387 value |= BCM43xx_DMA_RXCTRL_ENABLE;
388 bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value);
389 /* Set Receive Descriptor ring address. */
390 bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING,
391 ring->dmabase + ring->memoffset);
392 /* Init the descriptor pointer. */
393 bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200);
394 }
395
396out:
397 return err;
398}
399
400/* Shutdown the DMA controller. */
401static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
402{
403 if (ring->tx) {
404 bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
405 /* Zero out Transmit Descriptor ring address. */
406 bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0);
407 } else {
408 bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
409 /* Zero out Receive Descriptor ring address. */
410 bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0);
411 }
412}
413
414static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
415{
416 struct bcm43xx_dmadesc *desc;
417 struct bcm43xx_dmadesc_meta *meta;
418 int i;
419
420 if (!ring->used_slots)
421 return;
422 for (i = 0; i < ring->nr_slots; i++) {
423 desc = ring->vbase + i;
424 meta = ring->meta + i;
425
426 if (!meta->skb) {
427 assert(ring->tx);
428 continue;
429 }
430 if (ring->tx) {
431 unmap_descbuffer(ring, meta->dmaaddr,
432 meta->skb->len, 1);
433 } else {
434 unmap_descbuffer(ring, meta->dmaaddr,
435 ring->rx_buffersize, 0);
436 }
437 free_descriptor_buffer(ring, desc, meta, 0);
438 }
439}
440
441/* Main initialization function. */
442static
443struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
444 u16 dma_controller_base,
445 int nr_descriptor_slots,
446 int tx)
447{
448 struct bcm43xx_dmaring *ring;
449 int err;
450
451 ring = kzalloc(sizeof(*ring), GFP_KERNEL);
452 if (!ring)
453 goto out;
454
455 ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
456 GFP_KERNEL);
457 if (!ring->meta)
458 goto err_kfree_ring;
459
460 ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
461#ifdef CONFIG_BCM947XX
462 if (bcm->pci_dev->bus->number == 0)
463 ring->memoffset = 0;
464#endif
465
466 ring->bcm = bcm;
467 ring->nr_slots = nr_descriptor_slots;
468 ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
469 ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
470 assert(ring->suspend_mark < ring->resume_mark);
471 ring->mmio_base = dma_controller_base;
472 if (tx) {
473 ring->tx = 1;
474 ring->current_slot = -1;
475 } else {
476 switch (dma_controller_base) {
477 case BCM43xx_MMIO_DMA1_BASE:
478 ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
479 ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
480 break;
481 case BCM43xx_MMIO_DMA4_BASE:
482 ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
483 ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
484 break;
485 default:
486 assert(0);
487 }
488 }
489
490 err = alloc_ringmemory(ring);
491 if (err)
492 goto err_kfree_meta;
493 err = dmacontroller_setup(ring);
494 if (err)
495 goto err_free_ringmemory;
496
497out:
498 return ring;
499
500err_free_ringmemory:
501 free_ringmemory(ring);
502err_kfree_meta:
503 kfree(ring->meta);
504err_kfree_ring:
505 kfree(ring);
506 ring = NULL;
507 goto out;
508}
509
510/* Main cleanup function. */
511static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
512{
513 if (!ring)
514 return;
515
516 dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
517 ring->mmio_base,
518 (ring->tx) ? "TX" : "RX",
519 ring->max_used_slots, ring->nr_slots);
520 /* Device IRQs are disabled prior entering this function,
521 * so no need to take care of concurrency with rx handler stuff.
522 */
523 dmacontroller_cleanup(ring);
524 free_all_descbuffers(ring);
525 free_ringmemory(ring);
526
527 kfree(ring->meta);
528 kfree(ring);
529}
530
531void bcm43xx_dma_free(struct bcm43xx_private *bcm)
532{
533 struct bcm43xx_dma *dma;
534
535 if (bcm43xx_using_pio(bcm))
536 return;
537 dma = bcm43xx_current_dma(bcm);
538
539 bcm43xx_destroy_dmaring(dma->rx_ring1);
540 dma->rx_ring1 = NULL;
541 bcm43xx_destroy_dmaring(dma->rx_ring0);
542 dma->rx_ring0 = NULL;
543 bcm43xx_destroy_dmaring(dma->tx_ring3);
544 dma->tx_ring3 = NULL;
545 bcm43xx_destroy_dmaring(dma->tx_ring2);
546 dma->tx_ring2 = NULL;
547 bcm43xx_destroy_dmaring(dma->tx_ring1);
548 dma->tx_ring1 = NULL;
549 bcm43xx_destroy_dmaring(dma->tx_ring0);
550 dma->tx_ring0 = NULL;
551}
552
553int bcm43xx_dma_init(struct bcm43xx_private *bcm)
554{
555 struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
556 struct bcm43xx_dmaring *ring;
557 int err = -ENOMEM;
558
559 /* setup TX DMA channels. */
560 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
561 BCM43xx_TXRING_SLOTS, 1);
562 if (!ring)
563 goto out;
564 dma->tx_ring0 = ring;
565
566 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
567 BCM43xx_TXRING_SLOTS, 1);
568 if (!ring)
569 goto err_destroy_tx0;
570 dma->tx_ring1 = ring;
571
572 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
573 BCM43xx_TXRING_SLOTS, 1);
574 if (!ring)
575 goto err_destroy_tx1;
576 dma->tx_ring2 = ring;
577
578 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
579 BCM43xx_TXRING_SLOTS, 1);
580 if (!ring)
581 goto err_destroy_tx2;
582 dma->tx_ring3 = ring;
583
584 /* setup RX DMA channels. */
585 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
586 BCM43xx_RXRING_SLOTS, 0);
587 if (!ring)
588 goto err_destroy_tx3;
589 dma->rx_ring0 = ring;
590
591 if (bcm->current_core->rev < 5) {
592 ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
593 BCM43xx_RXRING_SLOTS, 0);
594 if (!ring)
595 goto err_destroy_rx0;
596 dma->rx_ring1 = ring;
597 }
598
599 dprintk(KERN_INFO PFX "DMA initialized\n");
600 err = 0;
601out:
602 return err;
603
604err_destroy_rx0:
605 bcm43xx_destroy_dmaring(dma->rx_ring0);
606 dma->rx_ring0 = NULL;
607err_destroy_tx3:
608 bcm43xx_destroy_dmaring(dma->tx_ring3);
609 dma->tx_ring3 = NULL;
610err_destroy_tx2:
611 bcm43xx_destroy_dmaring(dma->tx_ring2);
612 dma->tx_ring2 = NULL;
613err_destroy_tx1:
614 bcm43xx_destroy_dmaring(dma->tx_ring1);
615 dma->tx_ring1 = NULL;
616err_destroy_tx0:
617 bcm43xx_destroy_dmaring(dma->tx_ring0);
618 dma->tx_ring0 = NULL;
619 goto out;
620}
621
622/* Generate a cookie for the TX header. */
623static u16 generate_cookie(struct bcm43xx_dmaring *ring,
624 int slot)
625{
626 u16 cookie = 0x0000;
627
628 /* Use the upper 4 bits of the cookie as
629 * DMA controller ID and store the slot number
630 * in the lower 12 bits
631 */
632 switch (ring->mmio_base) {
633 default:
634 assert(0);
635 case BCM43xx_MMIO_DMA1_BASE:
636 break;
637 case BCM43xx_MMIO_DMA2_BASE:
638 cookie = 0x1000;
639 break;
640 case BCM43xx_MMIO_DMA3_BASE:
641 cookie = 0x2000;
642 break;
643 case BCM43xx_MMIO_DMA4_BASE:
644 cookie = 0x3000;
645 break;
646 }
647 assert(((u16)slot & 0xF000) == 0x0000);
648 cookie |= (u16)slot;
649
650 return cookie;
651}
652
653/* Inspect a cookie and find out to which controller/slot it belongs. */
654static
655struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
656 u16 cookie, int *slot)
657{
658 struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
659 struct bcm43xx_dmaring *ring = NULL;
660
661 switch (cookie & 0xF000) {
662 case 0x0000:
663 ring = dma->tx_ring0;
664 break;
665 case 0x1000:
666 ring = dma->tx_ring1;
667 break;
668 case 0x2000:
669 ring = dma->tx_ring2;
670 break;
671 case 0x3000:
672 ring = dma->tx_ring3;
673 break;
674 default:
675 assert(0);
676 }
677 *slot = (cookie & 0x0FFF);
678 assert(*slot >= 0 && *slot < ring->nr_slots);
679
680 return ring;
681}
682
683static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
684 int slot)
685{
686 /* Everything is ready to start. Buffers are DMA mapped and
687 * associated with slots.
688 * "slot" is the last slot of the new frame we want to transmit.
689 * Close your seat belts now, please.
690 */
691 wmb();
692 slot = next_slot(ring, slot);
693 bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX,
694 (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
695}
696
697static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
698 struct sk_buff *skb,
699 u8 cur_frag)
700{
701 int slot;
702 struct bcm43xx_dmadesc *desc;
703 struct bcm43xx_dmadesc_meta *meta;
704 u32 desc_ctl;
705 u32 desc_addr;
706
707 assert(skb_shinfo(skb)->nr_frags == 0);
708
709 slot = request_slot(ring);
710 desc = ring->vbase + slot;
711 meta = ring->meta + slot;
712
713 /* Add a device specific TX header. */
714 assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
715 /* Reserve enough headroom for the device tx header. */
716 __skb_push(skb, sizeof(struct bcm43xx_txhdr));
717 /* Now calculate and add the tx header.
718 * The tx header includes the PLCP header.
719 */
720 bcm43xx_generate_txhdr(ring->bcm,
721 (struct bcm43xx_txhdr *)skb->data,
722 skb->data + sizeof(struct bcm43xx_txhdr),
723 skb->len - sizeof(struct bcm43xx_txhdr),
724 (cur_frag == 0),
725 generate_cookie(ring, slot));
726
727 meta->skb = skb;
728 meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
729 if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
730 return_slot(ring, slot);
731 printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G "
732 "(0x%08x, len: %u)\n",
733 meta->dmaaddr, skb->len);
734 return -ENOMEM;
735 }
736
737 desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
738 desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
739 desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
740 desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
741 (u32)(meta->skb->len - ring->frameoffset));
742 if (slot == ring->nr_slots - 1)
743 desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
744
745 set_desc_ctl(desc, desc_ctl);
746 set_desc_addr(desc, desc_addr);
747 /* Now transfer the whole frame. */
748 dmacontroller_poke_tx(ring, slot);
749
750 return 0;
751}
752
753int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
754 struct ieee80211_txb *txb)
755{
756 /* We just received a packet from the kernel network subsystem.
757 * Add headers and DMA map the memory. Poke
758 * the device to send the stuff.
759 * Note that this is called from atomic context.
760 */
761 struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1;
762 u8 i;
763 struct sk_buff *skb;
764
765 assert(ring->tx);
766 if (unlikely(free_slots(ring) < txb->nr_frags)) {
767 /* The queue should be stopped,
768 * if we are low on free slots.
769 * If this ever triggers, we have to lower the suspend_mark.
770 */
771 dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n");
772 return -ENOMEM;
773 }
774
775 for (i = 0; i < txb->nr_frags; i++) {
776 skb = txb->fragments[i];
777 /* Take skb from ieee80211_txb_free */
778 txb->fragments[i] = NULL;
779 dma_tx_fragment(ring, skb, i);
780 //TODO: handle failure of dma_tx_fragment
781 }
782 ieee80211_txb_free(txb);
783
784 return 0;
785}
786
787void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
788 struct bcm43xx_xmitstatus *status)
789{
790 struct bcm43xx_dmaring *ring;
791 struct bcm43xx_dmadesc *desc;
792 struct bcm43xx_dmadesc_meta *meta;
793 int is_last_fragment;
794 int slot;
795
796 ring = parse_cookie(bcm, status->cookie, &slot);
797 assert(ring);
798 assert(ring->tx);
799 assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
800 while (1) {
801 assert(slot >= 0 && slot < ring->nr_slots);
802 desc = ring->vbase + slot;
803 meta = ring->meta + slot;
804
805 is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
806 unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
807 free_descriptor_buffer(ring, desc, meta, 1);
808 /* Everything belonging to the slot is unmapped
809 * and freed, so we can return it.
810 */
811 return_slot(ring, slot);
812
813 if (is_last_fragment)
814 break;
815 slot = next_slot(ring, slot);
816 }
817 bcm->stats.last_tx = jiffies;
818}
819
820static void dma_rx(struct bcm43xx_dmaring *ring,
821 int *slot)
822{
823 struct bcm43xx_dmadesc *desc;
824 struct bcm43xx_dmadesc_meta *meta;
825 struct bcm43xx_rxhdr *rxhdr;
826 struct sk_buff *skb;
827 u16 len;
828 int err;
829 dma_addr_t dmaaddr;
830
831 desc = ring->vbase + *slot;
832 meta = ring->meta + *slot;
833
834 sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
835 skb = meta->skb;
836
837 if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
838 /* We received an xmit status. */
839 struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
840 struct bcm43xx_xmitstatus stat;
841
842 stat.cookie = le16_to_cpu(hw->cookie);
843 stat.flags = hw->flags;
844 stat.cnt1 = hw->cnt1;
845 stat.cnt2 = hw->cnt2;
846 stat.seq = le16_to_cpu(hw->seq);
847 stat.unknown = le16_to_cpu(hw->unknown);
848
849 bcm43xx_debugfs_log_txstat(ring->bcm, &stat);
850 bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat);
851 /* recycle the descriptor buffer. */
852 sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize);
853
854 return;
855 }
856 rxhdr = (struct bcm43xx_rxhdr *)skb->data;
857 len = le16_to_cpu(rxhdr->frame_length);
858 if (len == 0) {
859 int i = 0;
860
861 do {
862 udelay(2);
863 barrier();
864 len = le16_to_cpu(rxhdr->frame_length);
865 } while (len == 0 && i++ < 5);
866 if (unlikely(len == 0)) {
867 /* recycle the descriptor buffer. */
868 sync_descbuffer_for_device(ring, meta->dmaaddr,
869 ring->rx_buffersize);
870 goto drop;
871 }
872 }
873 if (unlikely(len > ring->rx_buffersize)) {
874 /* The data did not fit into one descriptor buffer
875 * and is split over multiple buffers.
876 * This should never happen, as we try to allocate buffers
877 * big enough. So simply ignore this packet.
878 */
879 int cnt = 0;
880 s32 tmp = len;
881
882 while (1) {
883 desc = ring->vbase + *slot;
884 meta = ring->meta + *slot;
885 /* recycle the descriptor buffer. */
886 sync_descbuffer_for_device(ring, meta->dmaaddr,
887 ring->rx_buffersize);
888 *slot = next_slot(ring, *slot);
889 cnt++;
890 tmp -= ring->rx_buffersize;
891 if (tmp <= 0)
892 break;
893 }
894 printkl(KERN_ERR PFX "DMA RX buffer too small "
895 "(len: %u, buffer: %u, nr-dropped: %d)\n",
896 len, ring->rx_buffersize, cnt);
897 goto drop;
898 }
899 len -= IEEE80211_FCS_LEN;
900
901 dmaaddr = meta->dmaaddr;
902 err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
903 if (unlikely(err)) {
904 dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n");
905 sync_descbuffer_for_device(ring, dmaaddr,
906 ring->rx_buffersize);
907 goto drop;
908 }
909
910 unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
911 skb_put(skb, len + ring->frameoffset);
912 skb_pull(skb, ring->frameoffset);
913
914 err = bcm43xx_rx(ring->bcm, skb, rxhdr);
915 if (err) {
916 dev_kfree_skb_irq(skb);
917 goto drop;
918 }
919
920drop:
921 return;
922}
923
924void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
925{
926 u32 status;
927 u16 descptr;
928 int slot, current_slot;
929#ifdef CONFIG_BCM43XX_DEBUG
930 int used_slots = 0;
931#endif
932
933 assert(!ring->tx);
934 status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS);
935 descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
936 current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
937 assert(current_slot >= 0 && current_slot < ring->nr_slots);
938
939 slot = ring->current_slot;
940 for ( ; slot != current_slot; slot = next_slot(ring, slot)) {
941 dma_rx(ring, &slot);
942#ifdef CONFIG_BCM43XX_DEBUG
943 if (++used_slots > ring->max_used_slots)
944 ring->max_used_slots = used_slots;
945#endif
946 }
947 bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX,
948 (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
949 ring->current_slot = slot;
950}
951
952void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
953{
954 assert(ring->tx);
955 bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
956 bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
957 bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
958 | BCM43xx_DMA_TXCTRL_SUSPEND);
959}
960
961void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
962{
963 assert(ring->tx);
964 bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
965 bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
966 & ~BCM43xx_DMA_TXCTRL_SUSPEND);
967 bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
968}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
new file mode 100644
index 000000000000..2d520e4b0276
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
@@ -0,0 +1,218 @@
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#define BCM43xx_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
13 | (1 << 14) | (1 << 15))
14#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13)
15#define BCM43xx_DMAIRQ_RX_DONE (1 << 16)
16
17/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
18#define BCM43xx_DMA_TX_CONTROL 0x00
19#define BCM43xx_DMA_TX_DESC_RING 0x04
20#define BCM43xx_DMA_TX_DESC_INDEX 0x08
21#define BCM43xx_DMA_TX_STATUS 0x0c
22#define BCM43xx_DMA_RX_CONTROL 0x10
23#define BCM43xx_DMA_RX_DESC_RING 0x14
24#define BCM43xx_DMA_RX_DESC_INDEX 0x18
25#define BCM43xx_DMA_RX_STATUS 0x1c
26
27/* DMA controller channel control word values. */
28#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0)
29#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1)
30#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2)
31#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4)
32#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0)
33#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe
34#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1
35#define BCM43xx_DMA_RXCTRL_PIO (1 << 8)
36/* DMA controller channel status word values. */
37#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff
38#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000
39#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000
40#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000
41#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000
42#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000
43#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000
44#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000
45#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20)
46#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff
47#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000
48#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000
49#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000
50#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000
51#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000
52#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000
53#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000
54
55/* DMA descriptor control field values. */
56#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff
57#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */
58#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */
59#define BCM43xx_DMADTOR_FRAMEEND (1 << 30)
60#define BCM43xx_DMADTOR_FRAMESTART (1 << 31)
61
62/* Misc DMA constants */
63#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE
64#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF
65#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30)
66#define BCM43xx_DMA1_RX_FRAMEOFFSET 30
67#define BCM43xx_DMA4_RX_FRAMEOFFSET 0
68
69/* DMA engine tuning knobs */
70#define BCM43xx_TXRING_SLOTS 512
71#define BCM43xx_RXRING_SLOTS 64
72#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100)
73#define BCM43xx_DMA4_RXBUFFERSIZE 16
74/* Suspend the tx queue, if less than this percent slots are free. */
75#define BCM43xx_TXSUSPEND_PERCENT 20
76/* Resume the tx queue, if more than this percent slots are free. */
77#define BCM43xx_TXRESUME_PERCENT 50
78
79
80
81#ifdef CONFIG_BCM43XX_DMA
82
83
84struct sk_buff;
85struct bcm43xx_private;
86struct bcm43xx_xmitstatus;
87
88
89struct bcm43xx_dmadesc {
90 __le32 _control;
91 __le32 _address;
92} __attribute__((__packed__));
93
94/* Macros to access the bcm43xx_dmadesc struct */
95#define get_desc_ctl(desc) le32_to_cpu((desc)->_control)
96#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0)
97#define get_desc_addr(desc) le32_to_cpu((desc)->_address)
98#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0)
99
100struct bcm43xx_dmadesc_meta {
101 /* The kernel DMA-able buffer. */
102 struct sk_buff *skb;
103 /* DMA base bus-address of the descriptor buffer. */
104 dma_addr_t dmaaddr;
105};
106
107struct bcm43xx_dmaring {
108 struct bcm43xx_private *bcm;
109 /* Kernel virtual base address of the ring memory. */
110 struct bcm43xx_dmadesc *vbase;
111 /* DMA memory offset */
112 dma_addr_t memoffset;
113 /* (Unadjusted) DMA base bus-address of the ring memory. */
114 dma_addr_t dmabase;
115 /* Meta data about all descriptors. */
116 struct bcm43xx_dmadesc_meta *meta;
117 /* Number of descriptor slots in the ring. */
118 int nr_slots;
119 /* Number of used descriptor slots. */
120 int used_slots;
121 /* Currently used slot in the ring. */
122 int current_slot;
123 /* Marks to suspend/resume the queue. */
124 int suspend_mark;
125 int resume_mark;
126 /* Frameoffset in octets. */
127 u32 frameoffset;
128 /* Descriptor buffer size. */
129 u16 rx_buffersize;
130 /* The MMIO base register of the DMA controller, this
131 * ring is posted to.
132 */
133 u16 mmio_base;
134 u8 tx:1, /* TRUE, if this is a TX ring. */
135 suspended:1; /* TRUE, if transfers are suspended on this ring. */
136#ifdef CONFIG_BCM43XX_DEBUG
137 /* Maximum number of used slots. */
138 int max_used_slots;
139#endif /* CONFIG_BCM43XX_DEBUG*/
140};
141
142
143static inline
144u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
145 u16 offset)
146{
147 return bcm43xx_read32(ring->bcm, ring->mmio_base + offset);
148}
149
150static inline
151void bcm43xx_dma_write(struct bcm43xx_dmaring *ring,
152 u16 offset, u32 value)
153{
154 bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value);
155}
156
157
158int bcm43xx_dma_init(struct bcm43xx_private *bcm);
159void bcm43xx_dma_free(struct bcm43xx_private *bcm);
160
161int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
162 u16 dmacontroller_mmio_base);
163int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
164 u16 dmacontroller_mmio_base);
165
166void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
167void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
168
169void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
170 struct bcm43xx_xmitstatus *status);
171
172int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
173 struct ieee80211_txb *txb);
174void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
175
176
177#else /* CONFIG_BCM43XX_DMA */
178
179
180static inline
181int bcm43xx_dma_init(struct bcm43xx_private *bcm)
182{
183 return 0;
184}
185static inline
186void bcm43xx_dma_free(struct bcm43xx_private *bcm)
187{
188}
189static inline
190int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
191 u16 dmacontroller_mmio_base)
192{
193 return 0;
194}
195static inline
196int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
197 u16 dmacontroller_mmio_base)
198{
199 return 0;
200}
201static inline
202int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
203 struct ieee80211_txb *txb)
204{
205 return 0;
206}
207static inline
208void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
209 struct bcm43xx_xmitstatus *status)
210{
211}
212static inline
213void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
214{
215}
216
217#endif /* CONFIG_BCM43XX_DMA */
218#endif /* BCM43xx_DMA_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
new file mode 100644
index 000000000000..b3ffcf501311
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
@@ -0,0 +1,50 @@
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 ethtool support
6
7 Copyright (c) 2006 Jason Lunz <lunz@falooley.org>
8
9 Some code in this file is derived from the 8139too.c driver
10 Copyright (C) 2002 Jeff Garzik
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; see the file COPYING. If not, write to
24 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
25 Boston, MA 02110-1301, USA.
26
27*/
28
29#include "bcm43xx.h"
30#include "bcm43xx_ethtool.h"
31
32#include <linux/netdevice.h>
33#include <linux/pci.h>
34#include <linux/string.h>
35#include <linux/version.h>
36
37
38static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
39{
40 struct bcm43xx_private *bcm = bcm43xx_priv(dev);
41
42 strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
43 strncpy(info->version, UTS_RELEASE, sizeof(info->version));
44 strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
45}
46
47struct ethtool_ops bcm43xx_ethtool_ops = {
48 .get_drvinfo = bcm43xx_get_drvinfo,
49 .get_link = ethtool_op_get_link,
50};
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
new file mode 100644
index 000000000000..813704991f62
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
@@ -0,0 +1,8 @@
1#ifndef BCM43xx_ETHTOOL_H_
2#define BCM43xx_ETHTOOL_H_
3
4#include <linux/ethtool.h>
5
6extern struct ethtool_ops bcm43xx_ethtool_ops;
7
8#endif /* BCM43xx_ETHTOOL_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..ad8e569d1faf
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
@@ -0,0 +1,337 @@
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_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
316{
317 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
318 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
319 mmiowb();
320 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val);
321 } else {
322 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
323 mmiowb();
324 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val);
325 }
326}
327
328u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset)
329{
330 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
331 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
332 return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1);
333 } else {
334 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
335 return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1);
336 }
337}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
new file mode 100644
index 000000000000..464521abf73c
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
@@ -0,0 +1,32 @@
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_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
30u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset);
31
32#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..4b2c02c0b31e
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -0,0 +1,293 @@
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 const u16 mask = (1 << index);
39 u16 ledctl;
40
41 assert(index >= 0 && index < BCM43xx_NR_LEDS);
42 assert(led->blink_interval);
43 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
44 ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
45 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
46}
47
48static void bcm43xx_led_blink(unsigned long d)
49{
50 struct bcm43xx_led *led = (struct bcm43xx_led *)d;
51 struct bcm43xx_private *bcm = led->bcm;
52 unsigned long flags;
53
54 bcm43xx_lock_mmio(bcm, flags);
55 if (led->blink_interval) {
56 bcm43xx_led_changestate(led);
57 mod_timer(&led->blink_timer, jiffies + led->blink_interval);
58 }
59 bcm43xx_unlock_mmio(bcm, flags);
60}
61
62static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
63 unsigned long interval)
64{
65 if (led->blink_interval)
66 return;
67 led->blink_interval = interval;
68 bcm43xx_led_changestate(led);
69 led->blink_timer.expires = jiffies + interval;
70 add_timer(&led->blink_timer);
71}
72
73static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
74{
75 struct bcm43xx_private *bcm = led->bcm;
76 const int index = bcm43xx_led_index(led);
77 u16 ledctl;
78
79 if (!led->blink_interval)
80 return;
81 if (unlikely(sync))
82 del_timer_sync(&led->blink_timer);
83 else
84 del_timer(&led->blink_timer);
85 led->blink_interval = 0;
86
87 /* Make sure the LED is turned off. */
88 assert(index >= 0 && index < BCM43xx_NR_LEDS);
89 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
90 if (led->activelow)
91 ledctl |= (1 << index);
92 else
93 ledctl &= ~(1 << index);
94 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
95}
96
97static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
98 struct bcm43xx_led *led,
99 int led_index)
100{
101 /* This function is called, if the behaviour (and activelow)
102 * information for a LED is missing in the SPROM.
103 * We hardcode the behaviour values for various devices here.
104 * Note that the BCM43xx_LED_TEST_XXX behaviour values can
105 * be used to figure out which led is mapped to which index.
106 */
107
108 switch (led_index) {
109 case 0:
110 led->behaviour = BCM43xx_LED_ACTIVITY;
111 if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
112 led->behaviour = BCM43xx_LED_RADIO_ALL;
113 break;
114 case 1:
115 led->behaviour = BCM43xx_LED_RADIO_B;
116 if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
117 led->behaviour = BCM43xx_LED_ASSOC;
118 break;
119 case 2:
120 led->behaviour = BCM43xx_LED_RADIO_A;
121 break;
122 case 3:
123 led->behaviour = BCM43xx_LED_OFF;
124 break;
125 default:
126 assert(0);
127 }
128}
129
130int bcm43xx_leds_init(struct bcm43xx_private *bcm)
131{
132 struct bcm43xx_led *led;
133 u8 sprom[4];
134 int i;
135
136 sprom[0] = bcm->sprom.wl0gpio0;
137 sprom[1] = bcm->sprom.wl0gpio1;
138 sprom[2] = bcm->sprom.wl0gpio2;
139 sprom[3] = bcm->sprom.wl0gpio3;
140
141 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
142 led = &(bcm->leds[i]);
143 led->bcm = bcm;
144 setup_timer(&led->blink_timer,
145 bcm43xx_led_blink,
146 (unsigned long)led);
147
148 if (sprom[i] == 0xFF) {
149 bcm43xx_led_init_hardcoded(bcm, led, i);
150 } else {
151 led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
152 led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
153 }
154 }
155
156 return 0;
157}
158
159void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
160{
161 struct bcm43xx_led *led;
162 int i;
163
164 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
165 led = &(bcm->leds[i]);
166 bcm43xx_led_blink_stop(led, 1);
167 }
168 bcm43xx_leds_switch_all(bcm, 0);
169}
170
171void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
172{
173 struct bcm43xx_led *led;
174 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
175 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
176 const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
177 int i, turn_on;
178 unsigned long interval = 0;
179 u16 ledctl;
180
181 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
182 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
183 led = &(bcm->leds[i]);
184
185 turn_on = 0;
186 switch (led->behaviour) {
187 case BCM43xx_LED_INACTIVE:
188 continue;
189 case BCM43xx_LED_OFF:
190 break;
191 case BCM43xx_LED_ON:
192 turn_on = 1;
193 break;
194 case BCM43xx_LED_ACTIVITY:
195 turn_on = activity;
196 break;
197 case BCM43xx_LED_RADIO_ALL:
198 turn_on = radio->enabled;
199 break;
200 case BCM43xx_LED_RADIO_A:
201 turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
202 break;
203 case BCM43xx_LED_RADIO_B:
204 turn_on = (radio->enabled &&
205 (phy->type == BCM43xx_PHYTYPE_B ||
206 phy->type == BCM43xx_PHYTYPE_G));
207 break;
208 case BCM43xx_LED_MODE_BG:
209 if (phy->type == BCM43xx_PHYTYPE_G &&
210 1/*FIXME: using G rates.*/)
211 turn_on = 1;
212 break;
213 case BCM43xx_LED_TRANSFER:
214 if (transferring)
215 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
216 else
217 bcm43xx_led_blink_stop(led, 0);
218 continue;
219 case BCM43xx_LED_APTRANSFER:
220 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
221 if (transferring) {
222 interval = BCM43xx_LEDBLINK_FAST;
223 turn_on = 1;
224 }
225 } else {
226 turn_on = 1;
227 if (0/*TODO: not assoc*/)
228 interval = BCM43xx_LEDBLINK_SLOW;
229 else if (transferring)
230 interval = BCM43xx_LEDBLINK_FAST;
231 else
232 turn_on = 0;
233 }
234 if (turn_on)
235 bcm43xx_led_blink_start(led, interval);
236 else
237 bcm43xx_led_blink_stop(led, 0);
238 continue;
239 case BCM43xx_LED_WEIRD:
240 //TODO
241 break;
242 case BCM43xx_LED_ASSOC:
243 if (bcm->softmac->associated)
244 turn_on = 1;
245 break;
246#ifdef CONFIG_BCM43XX_DEBUG
247 case BCM43xx_LED_TEST_BLINKSLOW:
248 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
249 continue;
250 case BCM43xx_LED_TEST_BLINKMEDIUM:
251 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
252 continue;
253 case BCM43xx_LED_TEST_BLINKFAST:
254 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
255 continue;
256#endif /* CONFIG_BCM43XX_DEBUG */
257 default:
258 assert(0);
259 };
260
261 if (led->activelow)
262 turn_on = !turn_on;
263 if (turn_on)
264 ledctl |= (1 << i);
265 else
266 ledctl &= ~(1 << i);
267 }
268 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
269}
270
271void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
272{
273 struct bcm43xx_led *led;
274 u16 ledctl;
275 int i;
276 int bit_on;
277
278 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
279 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
280 led = &(bcm->leds[i]);
281 if (led->behaviour == BCM43xx_LED_INACTIVE)
282 continue;
283 if (on)
284 bit_on = led->activelow ? 0 : 1;
285 else
286 bit_on = led->activelow ? 1 : 0;
287 if (bit_on)
288 ledctl |= (1 << i);
289 else
290 ledctl &= ~(1 << i);
291 }
292 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
293}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
new file mode 100644
index 000000000000..d3716cf3aebc
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
@@ -0,0 +1,56 @@
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 / 1)
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 /* Behaviour values for testing.
42 * With these values it is easier to figure out
43 * the real behaviour of leds, in case the SPROM
44 * is missing information.
45 */
46 BCM43xx_LED_TEST_BLINKSLOW,
47 BCM43xx_LED_TEST_BLINKMEDIUM,
48 BCM43xx_LED_TEST_BLINKFAST,
49};
50
51int bcm43xx_leds_init(struct bcm43xx_private *bcm);
52void bcm43xx_leds_exit(struct bcm43xx_private *bcm);
53void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity);
54void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on);
55
56#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..c37371fc9e01
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -0,0 +1,3973 @@
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 <linux/dma-mapping.h>
42#include <net/iw_handler.h>
43
44#include "bcm43xx.h"
45#include "bcm43xx_main.h"
46#include "bcm43xx_debugfs.h"
47#include "bcm43xx_radio.h"
48#include "bcm43xx_phy.h"
49#include "bcm43xx_dma.h"
50#include "bcm43xx_pio.h"
51#include "bcm43xx_power.h"
52#include "bcm43xx_wx.h"
53#include "bcm43xx_ethtool.h"
54#include "bcm43xx_xmit.h"
55
56
57MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
58MODULE_AUTHOR("Martin Langer");
59MODULE_AUTHOR("Stefano Brivio");
60MODULE_AUTHOR("Michael Buesch");
61MODULE_LICENSE("GPL");
62
63#ifdef CONFIG_BCM947XX
64extern char *nvram_get(char *name);
65#endif
66
67#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
68static int modparam_pio;
69module_param_named(pio, modparam_pio, int, 0444);
70MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
71#elif defined(CONFIG_BCM43XX_DMA)
72# define modparam_pio 0
73#elif defined(CONFIG_BCM43XX_PIO)
74# define modparam_pio 1
75#endif
76
77static int modparam_bad_frames_preempt;
78module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
79MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");
80
81static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;
82module_param_named(short_retry, modparam_short_retry, int, 0444);
83MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
84
85static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;
86module_param_named(long_retry, modparam_long_retry, int, 0444);
87MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
88
89static int modparam_locale = -1;
90module_param_named(locale, modparam_locale, int, 0444);
91MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");
92
93static int modparam_noleds;
94module_param_named(noleds, modparam_noleds, int, 0444);
95MODULE_PARM_DESC(noleds, "Turn off all LED activity");
96
97#ifdef CONFIG_BCM43XX_DEBUG
98static char modparam_fwpostfix[64];
99module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
100MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
101#else
102# define modparam_fwpostfix ""
103#endif /* CONFIG_BCM43XX_DEBUG*/
104
105
106/* If you want to debug with just a single device, enable this,
107 * where the string is the pci device ID (as given by the kernel's
108 * pci_name function) of the device to be used.
109 */
110//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0"
111
112/* If you want to enable printing of each MMIO access, enable this. */
113//#define DEBUG_ENABLE_MMIO_PRINT
114
115/* If you want to enable printing of MMIO access within
116 * ucode/pcm upload, initvals write, enable this.
117 */
118//#define DEBUG_ENABLE_UCODE_MMIO_PRINT
119
120/* If you want to enable printing of PCI Config Space access, enable this */
121//#define DEBUG_ENABLE_PCILOG
122
123
124/* Detailed list maintained at:
125 * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices
126 */
127 static struct pci_device_id bcm43xx_pci_tbl[] = {
128 /* Broadcom 4303 802.11b */
129 { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
130 /* Broadcom 4307 802.11b */
131 { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
132 /* Broadcom 4318 802.11b/g */
133 { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
134 /* Broadcom 4306 802.11b/g */
135 { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
136 /* Broadcom 4306 802.11a */
137// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
138 /* Broadcom 4309 802.11a/b/g */
139 { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
140 /* Broadcom 43XG 802.11b/g */
141 { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
142#ifdef CONFIG_BCM947XX
143 /* SB bus on BCM947xx */
144 { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
145#endif
146 { 0 },
147};
148MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
149
150static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val)
151{
152 u32 status;
153
154 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
155 if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
156 val = swab32(val);
157
158 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
159 mmiowb();
160 bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);
161}
162
163static inline
164void bcm43xx_shm_control_word(struct bcm43xx_private *bcm,
165 u16 routing, u16 offset)
166{
167 u32 control;
168
169 /* "offset" is the WORD offset. */
170
171 control = routing;
172 control <<= 16;
173 control |= offset;
174 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);
175}
176
177u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
178 u16 routing, u16 offset)
179{
180 u32 ret;
181
182 if (routing == BCM43xx_SHM_SHARED) {
183 if (offset & 0x0003) {
184 /* Unaligned access */
185 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
186 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
187 ret <<= 16;
188 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
189 ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
190
191 return ret;
192 }
193 offset >>= 2;
194 }
195 bcm43xx_shm_control_word(bcm, routing, offset);
196 ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA);
197
198 return ret;
199}
200
201u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
202 u16 routing, u16 offset)
203{
204 u16 ret;
205
206 if (routing == BCM43xx_SHM_SHARED) {
207 if (offset & 0x0003) {
208 /* Unaligned access */
209 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
210 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED);
211
212 return ret;
213 }
214 offset >>= 2;
215 }
216 bcm43xx_shm_control_word(bcm, routing, offset);
217 ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA);
218
219 return ret;
220}
221
222void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
223 u16 routing, u16 offset,
224 u32 value)
225{
226 if (routing == BCM43xx_SHM_SHARED) {
227 if (offset & 0x0003) {
228 /* Unaligned access */
229 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
230 mmiowb();
231 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
232 (value >> 16) & 0xffff);
233 mmiowb();
234 bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1);
235 mmiowb();
236 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA,
237 value & 0xffff);
238 return;
239 }
240 offset >>= 2;
241 }
242 bcm43xx_shm_control_word(bcm, routing, offset);
243 mmiowb();
244 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);
245}
246
247void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
248 u16 routing, u16 offset,
249 u16 value)
250{
251 if (routing == BCM43xx_SHM_SHARED) {
252 if (offset & 0x0003) {
253 /* Unaligned access */
254 bcm43xx_shm_control_word(bcm, routing, offset >> 2);
255 mmiowb();
256 bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED,
257 value);
258 return;
259 }
260 offset >>= 2;
261 }
262 bcm43xx_shm_control_word(bcm, routing, offset);
263 mmiowb();
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 mmiowb();
323
324 /* Be careful with the in-progress timer.
325 * First zero out the low register, so we have a full
326 * register-overflow duration to complete the operation.
327 */
328 if (bcm->current_core->rev >= 3) {
329 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
330 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
331
332 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0);
333 mmiowb();
334 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi);
335 mmiowb();
336 bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo);
337 } else {
338 u16 v0 = (tsf & 0x000000000000FFFFULL);
339 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
340 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
341 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
342
343 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0);
344 mmiowb();
345 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3);
346 mmiowb();
347 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2);
348 mmiowb();
349 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1);
350 mmiowb();
351 bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
352 }
353
354 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
355 status &= ~BCM43xx_SBF_TIME_UPDATE;
356 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
357}
358
359static
360void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
361 u16 offset,
362 const u8 *mac)
363{
364 u16 data;
365
366 offset |= 0x0020;
367 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
368
369 data = mac[0];
370 data |= mac[1] << 8;
371 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
372 data = mac[2];
373 data |= mac[3] << 8;
374 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
375 data = mac[4];
376 data |= mac[5] << 8;
377 bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);
378}
379
380static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm,
381 u16 offset)
382{
383 const u8 zero_addr[ETH_ALEN] = { 0 };
384
385 bcm43xx_macfilter_set(bcm, offset, zero_addr);
386}
387
388static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
389{
390 const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr);
391 const u8 *bssid = (const u8 *)(bcm->ieee->bssid);
392 u8 mac_bssid[ETH_ALEN * 2];
393 int i;
394
395 memcpy(mac_bssid, mac, ETH_ALEN);
396 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
397
398 /* Write our MAC address and BSSID to template ram */
399 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
400 bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
401 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
402 bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
403 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
404 bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
405}
406
407//FIXME: Well, we should probably call them from somewhere.
408#if 0
409static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
410{
411 /* slot_time is in usec. */
412 if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G)
413 return;
414 bcm43xx_write16(bcm, 0x684, 510 + slot_time);
415 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);
416}
417
418static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm)
419{
420 bcm43xx_set_slot_time(bcm, 9);
421}
422
423static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
424{
425 bcm43xx_set_slot_time(bcm, 20);
426}
427#endif
428
429/* FIXME: To get the MAC-filter working, we need to implement the
430 * following functions (and rename them :)
431 */
432#if 0
433static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
434{
435 bcm43xx_mac_suspend(bcm);
436 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
437
438 bcm43xx_ram_write(bcm, 0x0026, 0x0000);
439 bcm43xx_ram_write(bcm, 0x0028, 0x0000);
440 bcm43xx_ram_write(bcm, 0x007E, 0x0000);
441 bcm43xx_ram_write(bcm, 0x0080, 0x0000);
442 bcm43xx_ram_write(bcm, 0x047E, 0x0000);
443 bcm43xx_ram_write(bcm, 0x0480, 0x0000);
444
445 if (bcm->current_core->rev < 3) {
446 bcm43xx_write16(bcm, 0x0610, 0x8000);
447 bcm43xx_write16(bcm, 0x060E, 0x0000);
448 } else
449 bcm43xx_write32(bcm, 0x0188, 0x80000000);
450
451 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
452
453 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G &&
454 ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
455 bcm43xx_short_slot_timing_enable(bcm);
456
457 bcm43xx_mac_enable(bcm);
458}
459
460static void bcm43xx_associate(struct bcm43xx_private *bcm,
461 const u8 *mac)
462{
463 memcpy(bcm->ieee->bssid, mac, ETH_ALEN);
464
465 bcm43xx_mac_suspend(bcm);
466 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
467 bcm43xx_write_mac_bssid_templates(bcm);
468 bcm43xx_mac_enable(bcm);
469}
470#endif
471
472/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
473 * Returns the _previously_ enabled IRQ mask.
474 */
475static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask)
476{
477 u32 old_mask;
478
479 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
480 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);
481
482 return old_mask;
483}
484
485/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
486 * Returns the _previously_ enabled IRQ mask.
487 */
488static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask)
489{
490 u32 old_mask;
491
492 old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
493 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
494
495 return old_mask;
496}
497
498/* Make sure we don't receive more data from the device. */
499static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
500{
501 u32 old;
502 unsigned long flags;
503
504 bcm43xx_lock_mmio(bcm, flags);
505 if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
506 bcm43xx_unlock_mmio(bcm, flags);
507 return -EBUSY;
508 }
509 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
510 tasklet_disable(&bcm->isr_tasklet);
511 bcm43xx_unlock_mmio(bcm, flags);
512 if (oldstate)
513 *oldstate = old;
514
515 return 0;
516}
517
518static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
519{
520 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
521 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
522 u32 radio_id;
523 u16 manufact;
524 u16 version;
525 u8 revision;
526 s8 i;
527
528 if (bcm->chip_id == 0x4317) {
529 if (bcm->chip_rev == 0x00)
530 radio_id = 0x3205017F;
531 else if (bcm->chip_rev == 0x01)
532 radio_id = 0x4205017F;
533 else
534 radio_id = 0x5205017F;
535 } else {
536 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
537 radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);
538 radio_id <<= 16;
539 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);
540 radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
541 }
542
543 manufact = (radio_id & 0x00000FFF);
544 version = (radio_id & 0x0FFFF000) >> 12;
545 revision = (radio_id & 0xF0000000) >> 28;
546
547 dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",
548 radio_id, manufact, version, revision);
549
550 switch (phy->type) {
551 case BCM43xx_PHYTYPE_A:
552 if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))
553 goto err_unsupported_radio;
554 break;
555 case BCM43xx_PHYTYPE_B:
556 if ((version & 0xFFF0) != 0x2050)
557 goto err_unsupported_radio;
558 break;
559 case BCM43xx_PHYTYPE_G:
560 if (version != 0x2050)
561 goto err_unsupported_radio;
562 break;
563 }
564
565 radio->manufact = manufact;
566 radio->version = version;
567 radio->revision = revision;
568
569 /* Set default attenuation values. */
570 radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
571 radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
572 radio->txctl1 = bcm43xx_default_txctl1(bcm);
573 radio->txctl2 = 0xFFFF;
574 if (phy->type == BCM43xx_PHYTYPE_A)
575 radio->txpower_desired = bcm->sprom.maxpower_aphy;
576 else
577 radio->txpower_desired = bcm->sprom.maxpower_bgphy;
578
579 /* Initialize the in-memory nrssi Lookup Table. */
580 for (i = 0; i < 64; i++)
581 radio->nrssi_lt[i] = i;
582
583 return 0;
584
585err_unsupported_radio:
586 printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");
587 return -ENODEV;
588}
589
590static const char * bcm43xx_locale_iso(u8 locale)
591{
592 /* ISO 3166-1 country codes.
593 * Note that there aren't ISO 3166-1 codes for
594 * all or locales. (Not all locales are countries)
595 */
596 switch (locale) {
597 case BCM43xx_LOCALE_WORLD:
598 case BCM43xx_LOCALE_ALL:
599 return "XX";
600 case BCM43xx_LOCALE_THAILAND:
601 return "TH";
602 case BCM43xx_LOCALE_ISRAEL:
603 return "IL";
604 case BCM43xx_LOCALE_JORDAN:
605 return "JO";
606 case BCM43xx_LOCALE_CHINA:
607 return "CN";
608 case BCM43xx_LOCALE_JAPAN:
609 case BCM43xx_LOCALE_JAPAN_HIGH:
610 return "JP";
611 case BCM43xx_LOCALE_USA_CANADA_ANZ:
612 case BCM43xx_LOCALE_USA_LOW:
613 return "US";
614 case BCM43xx_LOCALE_EUROPE:
615 return "EU";
616 case BCM43xx_LOCALE_NONE:
617 return " ";
618 }
619 assert(0);
620 return " ";
621}
622
623static const char * bcm43xx_locale_string(u8 locale)
624{
625 switch (locale) {
626 case BCM43xx_LOCALE_WORLD:
627 return "World";
628 case BCM43xx_LOCALE_THAILAND:
629 return "Thailand";
630 case BCM43xx_LOCALE_ISRAEL:
631 return "Israel";
632 case BCM43xx_LOCALE_JORDAN:
633 return "Jordan";
634 case BCM43xx_LOCALE_CHINA:
635 return "China";
636 case BCM43xx_LOCALE_JAPAN:
637 return "Japan";
638 case BCM43xx_LOCALE_USA_CANADA_ANZ:
639 return "USA/Canada/ANZ";
640 case BCM43xx_LOCALE_EUROPE:
641 return "Europe";
642 case BCM43xx_LOCALE_USA_LOW:
643 return "USAlow";
644 case BCM43xx_LOCALE_JAPAN_HIGH:
645 return "JapanHigh";
646 case BCM43xx_LOCALE_ALL:
647 return "All";
648 case BCM43xx_LOCALE_NONE:
649 return "None";
650 }
651 assert(0);
652 return "";
653}
654
655static inline u8 bcm43xx_crc8(u8 crc, u8 data)
656{
657 static const u8 t[] = {
658 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
659 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
660 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
661 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
662 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
663 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
664 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
665 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
666 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
667 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
668 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
669 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
670 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
671 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
672 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
673 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
674 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
675 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
676 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
677 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
678 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
679 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
680 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
681 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
682 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
683 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
684 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
685 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
686 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
687 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
688 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
689 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
690 };
691 return t[crc ^ data];
692}
693
694static u8 bcm43xx_sprom_crc(const u16 *sprom)
695{
696 int word;
697 u8 crc = 0xFF;
698
699 for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {
700 crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);
701 crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);
702 }
703 crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);
704 crc ^= 0xFF;
705
706 return crc;
707}
708
709int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom)
710{
711 int i;
712 u8 crc, expected_crc;
713
714 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
715 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
716 /* CRC-8 check. */
717 crc = bcm43xx_sprom_crc(sprom);
718 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
719 if (crc != expected_crc) {
720 printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "
721 "(0x%02X, expected: 0x%02X)\n",
722 crc, expected_crc);
723 return -EINVAL;
724 }
725
726 return 0;
727}
728
729int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
730{
731 int i, err;
732 u8 crc, expected_crc;
733 u32 spromctl;
734
735 /* CRC-8 validation of the input data. */
736 crc = bcm43xx_sprom_crc(sprom);
737 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
738 if (crc != expected_crc) {
739 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
740 return -EINVAL;
741 }
742
743 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
744 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
745 if (err)
746 goto err_ctlreg;
747 spromctl |= 0x10; /* SPROM WRITE enable. */
748 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
749 if (err)
750 goto err_ctlreg;
751 /* We must burn lots of CPU cycles here, but that does not
752 * really matter as one does not write the SPROM every other minute...
753 */
754 printk(KERN_INFO PFX "[ 0%%");
755 mdelay(500);
756 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
757 if (i == 16)
758 printk("25%%");
759 else if (i == 32)
760 printk("50%%");
761 else if (i == 48)
762 printk("75%%");
763 else if (i % 2)
764 printk(".");
765 bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
766 mmiowb();
767 mdelay(20);
768 }
769 spromctl &= ~0x10; /* SPROM WRITE enable. */
770 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
771 if (err)
772 goto err_ctlreg;
773 mdelay(500);
774 printk("100%% ]\n");
775 printk(KERN_INFO PFX "SPROM written.\n");
776 bcm43xx_controller_restart(bcm, "SPROM update");
777
778 return 0;
779err_ctlreg:
780 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
781 return -ENODEV;
782}
783
784static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
785{
786 u16 value;
787 u16 *sprom;
788#ifdef CONFIG_BCM947XX
789 char *c;
790#endif
791
792 sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
793 GFP_KERNEL);
794 if (!sprom) {
795 printk(KERN_ERR PFX "sprom_extract OOM\n");
796 return -ENOMEM;
797 }
798#ifdef CONFIG_BCM947XX
799 sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
800 sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
801
802 if ((c = nvram_get("il0macaddr")) != NULL)
803 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
804
805 if ((c = nvram_get("et1macaddr")) != NULL)
806 e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
807
808 sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
809 sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
810 sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
811
812 sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
813 sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
814 sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
815
816 sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
817#else
818 bcm43xx_sprom_read(bcm, sprom);
819#endif
820
821 /* boardflags2 */
822 value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
823 bcm->sprom.boardflags2 = value;
824
825 /* il0macaddr */
826 value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
827 *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
828 value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
829 *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
830 value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
831 *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
832
833 /* et0macaddr */
834 value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
835 *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
836 value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
837 *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
838 value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
839 *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
840
841 /* et1macaddr */
842 value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
843 *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
844 value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
845 *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
846 value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
847 *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
848
849 /* ethernet phy settings */
850 value = sprom[BCM43xx_SPROM_ETHPHY];
851 bcm->sprom.et0phyaddr = (value & 0x001F);
852 bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
853 bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
854 bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
855
856 /* boardrev, antennas, locale */
857 value = sprom[BCM43xx_SPROM_BOARDREV];
858 bcm->sprom.boardrev = (value & 0x00FF);
859 bcm->sprom.locale = (value & 0x0F00) >> 8;
860 bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;
861 bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;
862 if (modparam_locale != -1) {
863 if (modparam_locale >= 0 && modparam_locale <= 11) {
864 bcm->sprom.locale = modparam_locale;
865 printk(KERN_WARNING PFX "Operating with modified "
866 "LocaleCode %u (%s)\n",
867 bcm->sprom.locale,
868 bcm43xx_locale_string(bcm->sprom.locale));
869 } else {
870 printk(KERN_WARNING PFX "Module parameter \"locale\" "
871 "invalid value. (0 - 11)\n");
872 }
873 }
874
875 /* pa0b* */
876 value = sprom[BCM43xx_SPROM_PA0B0];
877 bcm->sprom.pa0b0 = value;
878 value = sprom[BCM43xx_SPROM_PA0B1];
879 bcm->sprom.pa0b1 = value;
880 value = sprom[BCM43xx_SPROM_PA0B2];
881 bcm->sprom.pa0b2 = value;
882
883 /* wl0gpio* */
884 value = sprom[BCM43xx_SPROM_WL0GPIO0];
885 if (value == 0x0000)
886 value = 0xFFFF;
887 bcm->sprom.wl0gpio0 = value & 0x00FF;
888 bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;
889 value = sprom[BCM43xx_SPROM_WL0GPIO2];
890 if (value == 0x0000)
891 value = 0xFFFF;
892 bcm->sprom.wl0gpio2 = value & 0x00FF;
893 bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;
894
895 /* maxpower */
896 value = sprom[BCM43xx_SPROM_MAXPWR];
897 bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;
898 bcm->sprom.maxpower_bgphy = value & 0x00FF;
899
900 /* pa1b* */
901 value = sprom[BCM43xx_SPROM_PA1B0];
902 bcm->sprom.pa1b0 = value;
903 value = sprom[BCM43xx_SPROM_PA1B1];
904 bcm->sprom.pa1b1 = value;
905 value = sprom[BCM43xx_SPROM_PA1B2];
906 bcm->sprom.pa1b2 = value;
907
908 /* idle tssi target */
909 value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];
910 bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;
911 bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;
912
913 /* boardflags */
914 value = sprom[BCM43xx_SPROM_BOARDFLAGS];
915 if (value == 0xFFFF)
916 value = 0x0000;
917 bcm->sprom.boardflags = value;
918 /* boardflags workarounds */
919 if (bcm->board_vendor == PCI_VENDOR_ID_DELL &&
920 bcm->chip_id == 0x4301 &&
921 bcm->board_revision == 0x74)
922 bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST;
923 if (bcm->board_vendor == PCI_VENDOR_ID_APPLE &&
924 bcm->board_type == 0x4E &&
925 bcm->board_revision > 0x40)
926 bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL;
927
928 /* antenna gain */
929 value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];
930 if (value == 0x0000 || value == 0xFFFF)
931 value = 0x0202;
932 /* convert values to Q5.2 */
933 bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;
934 bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;
935
936 kfree(sprom);
937
938 return 0;
939}
940
941static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
942{
943 struct ieee80211_geo geo;
944 struct ieee80211_channel *chan;
945 int have_a = 0, have_bg = 0;
946 int i;
947 u8 channel;
948 struct bcm43xx_phyinfo *phy;
949 const char *iso_country;
950
951 memset(&geo, 0, sizeof(geo));
952 for (i = 0; i < bcm->nr_80211_available; i++) {
953 phy = &(bcm->core_80211_ext[i].phy);
954 switch (phy->type) {
955 case BCM43xx_PHYTYPE_B:
956 case BCM43xx_PHYTYPE_G:
957 have_bg = 1;
958 break;
959 case BCM43xx_PHYTYPE_A:
960 have_a = 1;
961 break;
962 default:
963 assert(0);
964 }
965 }
966 iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
967
968 if (have_a) {
969 for (i = 0, channel = 0; channel < 201; channel++) {
970 chan = &geo.a[i++];
971 chan->freq = bcm43xx_channel_to_freq_a(channel);
972 chan->channel = channel;
973 }
974 geo.a_channels = i;
975 }
976 if (have_bg) {
977 for (i = 0, channel = 1; channel < 15; channel++) {
978 chan = &geo.bg[i++];
979 chan->freq = bcm43xx_channel_to_freq_bg(channel);
980 chan->channel = channel;
981 }
982 geo.bg_channels = i;
983 }
984 memcpy(geo.name, iso_country, 2);
985 if (0 /*TODO: Outdoor use only */)
986 geo.name[2] = 'O';
987 else if (0 /*TODO: Indoor use only */)
988 geo.name[2] = 'I';
989 else
990 geo.name[2] = ' ';
991 geo.name[3] = '\0';
992
993 ieee80211_set_geo(bcm->ieee, &geo);
994}
995
996/* DummyTransmission function, as documented on
997 * http://bcm-specs.sipsolutions.net/DummyTransmission
998 */
999void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
1000{
1001 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1002 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1003 unsigned int i, max_loop;
1004 u16 value = 0;
1005 u32 buffer[5] = {
1006 0x00000000,
1007 0x0000D400,
1008 0x00000000,
1009 0x00000001,
1010 0x00000000,
1011 };
1012
1013 switch (phy->type) {
1014 case BCM43xx_PHYTYPE_A:
1015 max_loop = 0x1E;
1016 buffer[0] = 0xCC010200;
1017 break;
1018 case BCM43xx_PHYTYPE_B:
1019 case BCM43xx_PHYTYPE_G:
1020 max_loop = 0xFA;
1021 buffer[0] = 0x6E840B00;
1022 break;
1023 default:
1024 assert(0);
1025 return;
1026 }
1027
1028 for (i = 0; i < 5; i++)
1029 bcm43xx_ram_write(bcm, i * 4, buffer[i]);
1030
1031 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
1032
1033 bcm43xx_write16(bcm, 0x0568, 0x0000);
1034 bcm43xx_write16(bcm, 0x07C0, 0x0000);
1035 bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0));
1036 bcm43xx_write16(bcm, 0x0508, 0x0000);
1037 bcm43xx_write16(bcm, 0x050A, 0x0000);
1038 bcm43xx_write16(bcm, 0x054C, 0x0000);
1039 bcm43xx_write16(bcm, 0x056A, 0x0014);
1040 bcm43xx_write16(bcm, 0x0568, 0x0826);
1041 bcm43xx_write16(bcm, 0x0500, 0x0000);
1042 bcm43xx_write16(bcm, 0x0502, 0x0030);
1043
1044 if (radio->version == 0x2050 && radio->revision <= 0x5)
1045 bcm43xx_radio_write16(bcm, 0x0051, 0x0017);
1046 for (i = 0x00; i < max_loop; i++) {
1047 value = bcm43xx_read16(bcm, 0x050E);
1048 if (value & 0x0080)
1049 break;
1050 udelay(10);
1051 }
1052 for (i = 0x00; i < 0x0A; i++) {
1053 value = bcm43xx_read16(bcm, 0x050E);
1054 if (value & 0x0400)
1055 break;
1056 udelay(10);
1057 }
1058 for (i = 0x00; i < 0x0A; i++) {
1059 value = bcm43xx_read16(bcm, 0x0690);
1060 if (!(value & 0x0100))
1061 break;
1062 udelay(10);
1063 }
1064 if (radio->version == 0x2050 && radio->revision <= 0x5)
1065 bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
1066}
1067
1068static void key_write(struct bcm43xx_private *bcm,
1069 u8 index, u8 algorithm, const u16 *key)
1070{
1071 unsigned int i, basic_wep = 0;
1072 u32 offset;
1073 u16 value;
1074
1075 /* Write associated key information */
1076 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2),
1077 ((index << 4) | (algorithm & 0x0F)));
1078
1079 /* The first 4 WEP keys need extra love */
1080 if (((algorithm == BCM43xx_SEC_ALGO_WEP) ||
1081 (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4))
1082 basic_wep = 1;
1083
1084 /* Write key payload, 8 little endian words */
1085 offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
1086 for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
1087 value = cpu_to_le16(key[i]);
1088 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1089 offset + (i * 2), value);
1090
1091 if (!basic_wep)
1092 continue;
1093
1094 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1095 offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE,
1096 value);
1097 }
1098}
1099
1100static void keymac_write(struct bcm43xx_private *bcm,
1101 u8 index, const u32 *addr)
1102{
1103 /* for keys 0-3 there is no associated mac address */
1104 if (index < 4)
1105 return;
1106
1107 index -= 4;
1108 if (bcm->current_core->rev >= 5) {
1109 bcm43xx_shm_write32(bcm,
1110 BCM43xx_SHM_HWMAC,
1111 index * 2,
1112 cpu_to_be32(*addr));
1113 bcm43xx_shm_write16(bcm,
1114 BCM43xx_SHM_HWMAC,
1115 (index * 2) + 1,
1116 cpu_to_be16(*((u16 *)(addr + 1))));
1117 } else {
1118 if (index < 8) {
1119 TODO(); /* Put them in the macaddress filter */
1120 } else {
1121 TODO();
1122 /* Put them BCM43xx_SHM_SHARED, stating index 0x0120.
1123 Keep in mind to update the count of keymacs in 0x003E as well! */
1124 }
1125 }
1126}
1127
1128static int bcm43xx_key_write(struct bcm43xx_private *bcm,
1129 u8 index, u8 algorithm,
1130 const u8 *_key, int key_len,
1131 const u8 *mac_addr)
1132{
1133 u8 key[BCM43xx_SEC_KEYSIZE] = { 0 };
1134
1135 if (index >= ARRAY_SIZE(bcm->key))
1136 return -EINVAL;
1137 if (key_len > ARRAY_SIZE(key))
1138 return -EINVAL;
1139 if (algorithm < 1 || algorithm > 5)
1140 return -EINVAL;
1141
1142 memcpy(key, _key, key_len);
1143 key_write(bcm, index, algorithm, (const u16 *)key);
1144 keymac_write(bcm, index, (const u32 *)mac_addr);
1145
1146 bcm->key[index].algorithm = algorithm;
1147
1148 return 0;
1149}
1150
1151static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
1152{
1153 static const u32 zero_mac[2] = { 0 };
1154 unsigned int i,j, nr_keys = 54;
1155 u16 offset;
1156
1157 if (bcm->current_core->rev < 5)
1158 nr_keys = 16;
1159 assert(nr_keys <= ARRAY_SIZE(bcm->key));
1160
1161 for (i = 0; i < nr_keys; i++) {
1162 bcm->key[i].enabled = 0;
1163 /* returns for i < 4 immediately */
1164 keymac_write(bcm, i, zero_mac);
1165 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1166 0x100 + (i * 2), 0x0000);
1167 for (j = 0; j < 8; j++) {
1168 offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE);
1169 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
1170 offset, 0x0000);
1171 }
1172 }
1173 dprintk(KERN_INFO PFX "Keys cleared\n");
1174}
1175
1176/* Lowlevel core-switch function. This is only to be used in
1177 * bcm43xx_switch_core() and bcm43xx_probe_cores()
1178 */
1179static int _switch_core(struct bcm43xx_private *bcm, int core)
1180{
1181 int err;
1182 int attempts = 0;
1183 u32 current_core;
1184
1185 assert(core >= 0);
1186 while (1) {
1187 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1188 (core * 0x1000) + 0x18000000);
1189 if (unlikely(err))
1190 goto error;
1191 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE,
1192 &current_core);
1193 if (unlikely(err))
1194 goto error;
1195 current_core = (current_core - 0x18000000) / 0x1000;
1196 if (current_core == core)
1197 break;
1198
1199 if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES))
1200 goto error;
1201 udelay(10);
1202 }
1203#ifdef CONFIG_BCM947XX
1204 if (bcm->pci_dev->bus->number == 0)
1205 bcm->current_core_offset = 0x1000 * core;
1206 else
1207 bcm->current_core_offset = 0;
1208#endif
1209
1210 return 0;
1211error:
1212 printk(KERN_ERR PFX "Failed to switch to core %d\n", core);
1213 return -ENODEV;
1214}
1215
1216int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core)
1217{
1218 int err;
1219
1220 if (unlikely(!new_core))
1221 return 0;
1222 if (!new_core->available)
1223 return -ENODEV;
1224 if (bcm->current_core == new_core)
1225 return 0;
1226 err = _switch_core(bcm, new_core->index);
1227 if (unlikely(err))
1228 goto out;
1229
1230 bcm->current_core = new_core;
1231 bcm->current_80211_core_idx = -1;
1232 if (new_core->id == BCM43xx_COREID_80211)
1233 bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
1234
1235out:
1236 return err;
1237}
1238
1239static int bcm43xx_core_enabled(struct bcm43xx_private *bcm)
1240{
1241 u32 value;
1242
1243 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1244 value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET
1245 | BCM43xx_SBTMSTATELOW_REJECT;
1246
1247 return (value == BCM43xx_SBTMSTATELOW_CLOCK);
1248}
1249
1250/* disable current core */
1251static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags)
1252{
1253 u32 sbtmstatelow;
1254 u32 sbtmstatehigh;
1255 int i;
1256
1257 /* fetch sbtmstatelow from core information registers */
1258 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1259
1260 /* core is already in reset */
1261 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET)
1262 goto out;
1263
1264 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) {
1265 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1266 BCM43xx_SBTMSTATELOW_REJECT;
1267 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1268
1269 for (i = 0; i < 1000; i++) {
1270 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1271 if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) {
1272 i = -1;
1273 break;
1274 }
1275 udelay(10);
1276 }
1277 if (i != -1) {
1278 printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n");
1279 return -EBUSY;
1280 }
1281
1282 for (i = 0; i < 1000; i++) {
1283 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1284 if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) {
1285 i = -1;
1286 break;
1287 }
1288 udelay(10);
1289 }
1290 if (i != -1) {
1291 printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n");
1292 return -EBUSY;
1293 }
1294
1295 sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1296 BCM43xx_SBTMSTATELOW_REJECT |
1297 BCM43xx_SBTMSTATELOW_RESET |
1298 BCM43xx_SBTMSTATELOW_CLOCK |
1299 core_flags;
1300 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1301 udelay(10);
1302 }
1303
1304 sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET |
1305 BCM43xx_SBTMSTATELOW_REJECT |
1306 core_flags;
1307 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1308
1309out:
1310 bcm->current_core->enabled = 0;
1311
1312 return 0;
1313}
1314
1315/* enable (reset) current core */
1316static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags)
1317{
1318 u32 sbtmstatelow;
1319 u32 sbtmstatehigh;
1320 u32 sbimstate;
1321 int err;
1322
1323 err = bcm43xx_core_disable(bcm, core_flags);
1324 if (err)
1325 goto out;
1326
1327 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1328 BCM43xx_SBTMSTATELOW_RESET |
1329 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1330 core_flags;
1331 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1332 udelay(1);
1333
1334 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
1335 if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) {
1336 sbtmstatehigh = 0x00000000;
1337 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh);
1338 }
1339
1340 sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE);
1341 if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) {
1342 sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT);
1343 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate);
1344 }
1345
1346 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK |
1347 BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK |
1348 core_flags;
1349 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1350 udelay(1);
1351
1352 sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags;
1353 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1354 udelay(1);
1355
1356 bcm->current_core->enabled = 1;
1357 assert(err == 0);
1358out:
1359 return err;
1360}
1361
1362/* http://bcm-specs.sipsolutions.net/80211CoreReset */
1363void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
1364{
1365 u32 flags = 0x00040000;
1366
1367 if ((bcm43xx_core_enabled(bcm)) &&
1368 !bcm43xx_using_pio(bcm)) {
1369//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
1370#ifndef CONFIG_BCM947XX
1371 /* reset all used DMA controllers. */
1372 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1373 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
1374 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
1375 bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1376 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
1377 if (bcm->current_core->rev < 5)
1378 bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
1379#endif
1380 }
1381 if (bcm->shutting_down) {
1382 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1383 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1384 & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
1385 } else {
1386 if (connect_phy)
1387 flags |= 0x20000000;
1388 bcm43xx_phy_connect(bcm, connect_phy);
1389 bcm43xx_core_enable(bcm, flags);
1390 bcm43xx_write16(bcm, 0x03E6, 0x0000);
1391 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
1392 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
1393 | BCM43xx_SBF_400);
1394 }
1395}
1396
1397static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1398{
1399 bcm43xx_radio_turn_off(bcm);
1400 bcm43xx_write16(bcm, 0x03E6, 0x00F4);
1401 bcm43xx_core_disable(bcm, 0);
1402}
1403
1404/* Mark the current 80211 core inactive.
1405 * "active_80211_core" is the other 80211 core, which is used.
1406 */
1407static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1408 struct bcm43xx_coreinfo *active_80211_core)
1409{
1410 u32 sbtmstatelow;
1411 struct bcm43xx_coreinfo *old_core;
1412 int err = 0;
1413
1414 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1415 bcm43xx_radio_turn_off(bcm);
1416 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1417 sbtmstatelow &= ~0x200a0000;
1418 sbtmstatelow |= 0xa0000;
1419 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1420 udelay(1);
1421 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1422 sbtmstatelow &= ~0xa0000;
1423 sbtmstatelow |= 0x80000;
1424 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1425 udelay(1);
1426
1427 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
1428 old_core = bcm->current_core;
1429 err = bcm43xx_switch_core(bcm, active_80211_core);
1430 if (err)
1431 goto out;
1432 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1433 sbtmstatelow &= ~0x20000000;
1434 sbtmstatelow |= 0x20000000;
1435 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1436 err = bcm43xx_switch_core(bcm, old_core);
1437 }
1438
1439out:
1440 return err;
1441}
1442
1443static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
1444{
1445 u32 v0, v1;
1446 u16 tmp;
1447 struct bcm43xx_xmitstatus stat;
1448
1449 while (1) {
1450 v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
1451 if (!v0)
1452 break;
1453 v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
1454
1455 stat.cookie = (v0 >> 16) & 0x0000FFFF;
1456 tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));
1457 stat.flags = tmp & 0xFF;
1458 stat.cnt1 = (tmp & 0x0F00) >> 8;
1459 stat.cnt2 = (tmp & 0xF000) >> 12;
1460 stat.seq = (u16)(v1 & 0xFFFF);
1461 stat.unknown = (u16)((v1 >> 16) & 0xFF);
1462
1463 bcm43xx_debugfs_log_txstat(bcm, &stat);
1464
1465 if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
1466 continue;
1467 if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
1468 //TODO: packet was not acked (was lost)
1469 }
1470 //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
1471
1472 if (bcm43xx_using_pio(bcm))
1473 bcm43xx_pio_handle_xmitstatus(bcm, &stat);
1474 else
1475 bcm43xx_dma_handle_xmitstatus(bcm, &stat);
1476 }
1477}
1478
1479static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
1480{
1481 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
1482 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);
1483 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1484 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));
1485 assert(bcm->noisecalc.core_at_start == bcm->current_core);
1486 assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);
1487}
1488
1489static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm)
1490{
1491 /* Top half of Link Quality calculation. */
1492
1493 if (bcm->noisecalc.calculation_running)
1494 return;
1495 bcm->noisecalc.core_at_start = bcm->current_core;
1496 bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;
1497 bcm->noisecalc.calculation_running = 1;
1498 bcm->noisecalc.nr_samples = 0;
1499
1500 bcm43xx_generate_noise_sample(bcm);
1501}
1502
1503static void handle_irq_noise(struct bcm43xx_private *bcm)
1504{
1505 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1506 u16 tmp;
1507 u8 noise[4];
1508 u8 i, j;
1509 s32 average;
1510
1511 /* Bottom half of Link Quality calculation. */
1512
1513 assert(bcm->noisecalc.calculation_running);
1514 if (bcm->noisecalc.core_at_start != bcm->current_core ||
1515 bcm->noisecalc.channel_at_start != radio->channel)
1516 goto drop_calculation;
1517 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);
1518 noise[0] = (tmp & 0x00FF);
1519 noise[1] = (tmp & 0xFF00) >> 8;
1520 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);
1521 noise[2] = (tmp & 0x00FF);
1522 noise[3] = (tmp & 0xFF00) >> 8;
1523 if (noise[0] == 0x7F || noise[1] == 0x7F ||
1524 noise[2] == 0x7F || noise[3] == 0x7F)
1525 goto generate_new;
1526
1527 /* Get the noise samples. */
1528 assert(bcm->noisecalc.nr_samples <= 8);
1529 i = bcm->noisecalc.nr_samples;
1530 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1531 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1532 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1533 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
1534 bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];
1535 bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];
1536 bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];
1537 bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];
1538 bcm->noisecalc.nr_samples++;
1539 if (bcm->noisecalc.nr_samples == 8) {
1540 /* Calculate the Link Quality by the noise samples. */
1541 average = 0;
1542 for (i = 0; i < 8; i++) {
1543 for (j = 0; j < 4; j++)
1544 average += bcm->noisecalc.samples[i][j];
1545 }
1546 average /= (8 * 4);
1547 average *= 125;
1548 average += 64;
1549 average /= 128;
1550
1551 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
1552 tmp = (tmp / 128) & 0x1F;
1553 if (tmp >= 8)
1554 average += 2;
1555 else
1556 average -= 25;
1557 if (tmp == 8)
1558 average -= 72;
1559 else
1560 average -= 48;
1561
1562/* FIXME: This is wrong, but people want fancy stats. well... */
1563bcm->stats.noise = average;
1564 if (average > -65)
1565 bcm->stats.link_quality = 0;
1566 else if (average > -75)
1567 bcm->stats.link_quality = 1;
1568 else if (average > -85)
1569 bcm->stats.link_quality = 2;
1570 else
1571 bcm->stats.link_quality = 3;
1572// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
1573drop_calculation:
1574 bcm->noisecalc.calculation_running = 0;
1575 return;
1576 }
1577generate_new:
1578 bcm43xx_generate_noise_sample(bcm);
1579}
1580
1581static void handle_irq_ps(struct bcm43xx_private *bcm)
1582{
1583 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
1584 ///TODO: PS TBTT
1585 } else {
1586 if (1/*FIXME: the last PSpoll frame was sent successfully */)
1587 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
1588 }
1589 if (bcm->ieee->iw_mode == IW_MODE_ADHOC)
1590 bcm->reg124_set_0x4 = 1;
1591 //FIXME else set to false?
1592}
1593
1594static void handle_irq_reg124(struct bcm43xx_private *bcm)
1595{
1596 if (!bcm->reg124_set_0x4)
1597 return;
1598 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,
1599 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)
1600 | 0x4);
1601 //FIXME: reset reg124_set_0x4 to false?
1602}
1603
1604static void handle_irq_pmq(struct bcm43xx_private *bcm)
1605{
1606 u32 tmp;
1607
1608 //TODO: AP mode.
1609
1610 while (1) {
1611 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);
1612 if (!(tmp & 0x00000008))
1613 break;
1614 }
1615 /* 16bit write is odd, but correct. */
1616 bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
1617}
1618
1619static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,
1620 u16 ram_offset, u16 shm_size_offset)
1621{
1622 u32 value;
1623 u16 size = 0;
1624
1625 /* Timestamp. */
1626 //FIXME: assumption: The chip sets the timestamp
1627 value = 0;
1628 bcm43xx_ram_write(bcm, ram_offset++, value);
1629 bcm43xx_ram_write(bcm, ram_offset++, value);
1630 size += 8;
1631
1632 /* Beacon Interval / Capability Information */
1633 value = 0x0000;//FIXME: Which interval?
1634 value |= (1 << 0) << 16; /* ESS */
1635 value |= (1 << 2) << 16; /* CF Pollable */ //FIXME?
1636 value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME?
1637 if (!bcm->ieee->open_wep)
1638 value |= (1 << 4) << 16; /* Privacy */
1639 bcm43xx_ram_write(bcm, ram_offset++, value);
1640 size += 4;
1641
1642 /* SSID */
1643 //TODO
1644
1645 /* FH Parameter Set */
1646 //TODO
1647
1648 /* DS Parameter Set */
1649 //TODO
1650
1651 /* CF Parameter Set */
1652 //TODO
1653
1654 /* TIM */
1655 //TODO
1656
1657 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
1658}
1659
1660static void handle_irq_beacon(struct bcm43xx_private *bcm)
1661{
1662 u32 status;
1663
1664 bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
1665 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
1666
1667 if ((status & 0x1) && (status & 0x2)) {
1668 /* ACK beacon IRQ. */
1669 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
1670 BCM43xx_IRQ_BEACON);
1671 bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
1672 return;
1673 }
1674 if (!(status & 0x1)) {
1675 bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);
1676 status |= 0x1;
1677 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1678 }
1679 if (!(status & 0x2)) {
1680 bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);
1681 status |= 0x2;
1682 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
1683 }
1684}
1685
1686/* Interrupt handler bottom-half */
1687static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
1688{
1689 u32 reason;
1690 u32 dma_reason[4];
1691 int activity = 0;
1692 unsigned long flags;
1693
1694#ifdef CONFIG_BCM43XX_DEBUG
1695 u32 _handled = 0x00000000;
1696# define bcmirq_handled(irq) do { _handled |= (irq); } while (0)
1697#else
1698# define bcmirq_handled(irq) do { /* nothing */ } while (0)
1699#endif /* CONFIG_BCM43XX_DEBUG*/
1700
1701 bcm43xx_lock_mmio(bcm, flags);
1702 reason = bcm->irq_reason;
1703 dma_reason[0] = bcm->dma_reason[0];
1704 dma_reason[1] = bcm->dma_reason[1];
1705 dma_reason[2] = bcm->dma_reason[2];
1706 dma_reason[3] = bcm->dma_reason[3];
1707
1708 if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
1709 /* TX error. We get this when Template Ram is written in wrong endianess
1710 * in dummy_tx(). We also get this if something is wrong with the TX header
1711 * on DMA or PIO queues.
1712 * Maybe we get this in other error conditions, too.
1713 */
1714 printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
1715 bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
1716 }
1717 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
1718 (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
1719 (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
1720 (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
1721 printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
1722 "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1723 dma_reason[0], dma_reason[1],
1724 dma_reason[2], dma_reason[3]);
1725 bcm43xx_controller_restart(bcm, "DMA error");
1726 bcm43xx_unlock_mmio(bcm, flags);
1727 return;
1728 }
1729 if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
1730 (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
1731 (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
1732 (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
1733 printkl(KERN_ERR PFX "DMA error: "
1734 "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
1735 dma_reason[0], dma_reason[1],
1736 dma_reason[2], dma_reason[3]);
1737 }
1738
1739 if (reason & BCM43xx_IRQ_PS) {
1740 handle_irq_ps(bcm);
1741 bcmirq_handled(BCM43xx_IRQ_PS);
1742 }
1743
1744 if (reason & BCM43xx_IRQ_REG124) {
1745 handle_irq_reg124(bcm);
1746 bcmirq_handled(BCM43xx_IRQ_REG124);
1747 }
1748
1749 if (reason & BCM43xx_IRQ_BEACON) {
1750 if (bcm->ieee->iw_mode == IW_MODE_MASTER)
1751 handle_irq_beacon(bcm);
1752 bcmirq_handled(BCM43xx_IRQ_BEACON);
1753 }
1754
1755 if (reason & BCM43xx_IRQ_PMQ) {
1756 handle_irq_pmq(bcm);
1757 bcmirq_handled(BCM43xx_IRQ_PMQ);
1758 }
1759
1760 if (reason & BCM43xx_IRQ_SCAN) {
1761 /*TODO*/
1762 //bcmirq_handled(BCM43xx_IRQ_SCAN);
1763 }
1764
1765 if (reason & BCM43xx_IRQ_NOISE) {
1766 handle_irq_noise(bcm);
1767 bcmirq_handled(BCM43xx_IRQ_NOISE);
1768 }
1769
1770 /* Check the DMA reason registers for received data. */
1771 assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
1772 assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
1773 if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
1774 if (bcm43xx_using_pio(bcm))
1775 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
1776 else
1777 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
1778 /* We intentionally don't set "activity" to 1, here. */
1779 }
1780 if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
1781 if (bcm43xx_using_pio(bcm))
1782 bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
1783 else
1784 bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
1785 activity = 1;
1786 }
1787 bcmirq_handled(BCM43xx_IRQ_RX);
1788
1789 if (reason & BCM43xx_IRQ_XMIT_STATUS) {
1790 handle_irq_transmit_status(bcm);
1791 activity = 1;
1792 //TODO: In AP mode, this also causes sending of powersave responses.
1793 bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
1794 }
1795
1796 /* IRQ_PIO_WORKAROUND is handled in the top-half. */
1797 bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
1798#ifdef CONFIG_BCM43XX_DEBUG
1799 if (unlikely(reason & ~_handled)) {
1800 printkl(KERN_WARNING PFX
1801 "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, "
1802 "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1803 reason, (reason & ~_handled),
1804 dma_reason[0], dma_reason[1],
1805 dma_reason[2], dma_reason[3]);
1806 }
1807#endif
1808#undef bcmirq_handled
1809
1810 if (!modparam_noleds)
1811 bcm43xx_leds_update(bcm, activity);
1812 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
1813 bcm43xx_unlock_mmio(bcm, flags);
1814}
1815
1816static void pio_irq_workaround(struct bcm43xx_private *bcm,
1817 u16 base, int queueidx)
1818{
1819 u16 rxctl;
1820
1821 rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);
1822 if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)
1823 bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;
1824 else
1825 bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;
1826}
1827
1828static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
1829{
1830 if (bcm43xx_using_pio(bcm) &&
1831 (bcm->current_core->rev < 3) &&
1832 (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
1833 /* Apply a PIO specific workaround to the dma_reasons */
1834 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);
1835 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);
1836 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);
1837 pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);
1838 }
1839
1840 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
1841
1842 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
1843 bcm->dma_reason[0]);
1844 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
1845 bcm->dma_reason[1]);
1846 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
1847 bcm->dma_reason[2]);
1848 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
1849 bcm->dma_reason[3]);
1850}
1851
1852/* Interrupt handler top-half */
1853static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
1854{
1855 irqreturn_t ret = IRQ_HANDLED;
1856 struct bcm43xx_private *bcm = dev_id;
1857 u32 reason;
1858
1859 if (!bcm)
1860 return IRQ_NONE;
1861
1862 spin_lock(&bcm->_lock);
1863
1864 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
1865 if (reason == 0xffffffff) {
1866 /* irq not for us (shared irq) */
1867 ret = IRQ_NONE;
1868 goto out;
1869 }
1870 reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
1871 if (!reason)
1872 goto out;
1873
1874 bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
1875 & 0x0001dc00;
1876 bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
1877 & 0x0000dc00;
1878 bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
1879 & 0x0000dc00;
1880 bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
1881 & 0x0001dc00;
1882
1883 bcm43xx_interrupt_ack(bcm, reason);
1884
1885 /* Only accept IRQs, if we are initialized properly.
1886 * This avoids an RX race while initializing.
1887 * We should probably not enable IRQs before we are initialized
1888 * completely, but some careful work is needed to fix this. I think it
1889 * is best to stay with this cheap workaround for now... .
1890 */
1891 if (likely(bcm->initialized)) {
1892 /* disable all IRQs. They are enabled again in the bottom half. */
1893 bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1894 /* save the reason code and call our bottom half. */
1895 bcm->irq_reason = reason;
1896 tasklet_schedule(&bcm->isr_tasklet);
1897 }
1898
1899out:
1900 mmiowb();
1901 spin_unlock(&bcm->_lock);
1902
1903 return ret;
1904}
1905
1906static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
1907{
1908 if (bcm->firmware_norelease && !force)
1909 return; /* Suspending or controller reset. */
1910 release_firmware(bcm->ucode);
1911 bcm->ucode = NULL;
1912 release_firmware(bcm->pcm);
1913 bcm->pcm = NULL;
1914 release_firmware(bcm->initvals0);
1915 bcm->initvals0 = NULL;
1916 release_firmware(bcm->initvals1);
1917 bcm->initvals1 = NULL;
1918}
1919
1920static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1921{
1922 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1923 u8 rev = bcm->current_core->rev;
1924 int err = 0;
1925 int nr;
1926 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
1927
1928 if (!bcm->ucode) {
1929 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
1930 (rev >= 5 ? 5 : rev),
1931 modparam_fwpostfix);
1932 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
1933 if (err) {
1934 printk(KERN_ERR PFX
1935 "Error: Microcode \"%s\" not available or load failed.\n",
1936 buf);
1937 goto error;
1938 }
1939 }
1940
1941 if (!bcm->pcm) {
1942 snprintf(buf, ARRAY_SIZE(buf),
1943 "bcm43xx_pcm%d%s.fw",
1944 (rev < 5 ? 4 : 5),
1945 modparam_fwpostfix);
1946 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
1947 if (err) {
1948 printk(KERN_ERR PFX
1949 "Error: PCM \"%s\" not available or load failed.\n",
1950 buf);
1951 goto error;
1952 }
1953 }
1954
1955 if (!bcm->initvals0) {
1956 if (rev == 2 || rev == 4) {
1957 switch (phy->type) {
1958 case BCM43xx_PHYTYPE_A:
1959 nr = 3;
1960 break;
1961 case BCM43xx_PHYTYPE_B:
1962 case BCM43xx_PHYTYPE_G:
1963 nr = 1;
1964 break;
1965 default:
1966 goto err_noinitval;
1967 }
1968
1969 } else if (rev >= 5) {
1970 switch (phy->type) {
1971 case BCM43xx_PHYTYPE_A:
1972 nr = 7;
1973 break;
1974 case BCM43xx_PHYTYPE_B:
1975 case BCM43xx_PHYTYPE_G:
1976 nr = 5;
1977 break;
1978 default:
1979 goto err_noinitval;
1980 }
1981 } else
1982 goto err_noinitval;
1983 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
1984 nr, modparam_fwpostfix);
1985
1986 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
1987 if (err) {
1988 printk(KERN_ERR PFX
1989 "Error: InitVals \"%s\" not available or load failed.\n",
1990 buf);
1991 goto error;
1992 }
1993 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
1994 printk(KERN_ERR PFX "InitVals fileformat error.\n");
1995 goto error;
1996 }
1997 }
1998
1999 if (!bcm->initvals1) {
2000 if (rev >= 5) {
2001 u32 sbtmstatehigh;
2002
2003 switch (phy->type) {
2004 case BCM43xx_PHYTYPE_A:
2005 sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
2006 if (sbtmstatehigh & 0x00010000)
2007 nr = 9;
2008 else
2009 nr = 10;
2010 break;
2011 case BCM43xx_PHYTYPE_B:
2012 case BCM43xx_PHYTYPE_G:
2013 nr = 6;
2014 break;
2015 default:
2016 goto err_noinitval;
2017 }
2018 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2019 nr, modparam_fwpostfix);
2020
2021 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
2022 if (err) {
2023 printk(KERN_ERR PFX
2024 "Error: InitVals \"%s\" not available or load failed.\n",
2025 buf);
2026 goto error;
2027 }
2028 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
2029 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2030 goto error;
2031 }
2032 }
2033 }
2034
2035out:
2036 return err;
2037error:
2038 bcm43xx_release_firmware(bcm, 1);
2039 goto out;
2040err_noinitval:
2041 printk(KERN_ERR PFX "Error: No InitVals available!\n");
2042 err = -ENOENT;
2043 goto error;
2044}
2045
2046static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2047{
2048 const u32 *data;
2049 unsigned int i, len;
2050
2051 /* Upload Microcode. */
2052 data = (u32 *)(bcm->ucode->data);
2053 len = bcm->ucode->size / sizeof(u32);
2054 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2055 for (i = 0; i < len; i++) {
2056 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2057 be32_to_cpu(data[i]));
2058 udelay(10);
2059 }
2060
2061 /* Upload PCM data. */
2062 data = (u32 *)(bcm->pcm->data);
2063 len = bcm->pcm->size / sizeof(u32);
2064 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2065 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2066 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
2067 for (i = 0; i < len; i++) {
2068 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
2069 be32_to_cpu(data[i]));
2070 udelay(10);
2071 }
2072}
2073
2074static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
2075 const struct bcm43xx_initval *data,
2076 const unsigned int len)
2077{
2078 u16 offset, size;
2079 u32 value;
2080 unsigned int i;
2081
2082 for (i = 0; i < len; i++) {
2083 offset = be16_to_cpu(data[i].offset);
2084 size = be16_to_cpu(data[i].size);
2085 value = be32_to_cpu(data[i].value);
2086
2087 if (unlikely(offset >= 0x1000))
2088 goto err_format;
2089 if (size == 2) {
2090 if (unlikely(value & 0xFFFF0000))
2091 goto err_format;
2092 bcm43xx_write16(bcm, offset, (u16)value);
2093 } else if (size == 4) {
2094 bcm43xx_write32(bcm, offset, value);
2095 } else
2096 goto err_format;
2097 }
2098
2099 return 0;
2100
2101err_format:
2102 printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "
2103 "Please fix your bcm43xx firmware files.\n");
2104 return -EPROTO;
2105}
2106
2107static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
2108{
2109 int err;
2110
2111 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
2112 bcm->initvals0->size / sizeof(struct bcm43xx_initval));
2113 if (err)
2114 goto out;
2115 if (bcm->initvals1) {
2116 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
2117 bcm->initvals1->size / sizeof(struct bcm43xx_initval));
2118 if (err)
2119 goto out;
2120 }
2121out:
2122 return err;
2123}
2124
2125static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2126{
2127 int res;
2128 unsigned int i;
2129 u32 data;
2130
2131 bcm->irq = bcm->pci_dev->irq;
2132#ifdef CONFIG_BCM947XX
2133 if (bcm->pci_dev->bus->number == 0) {
2134 struct pci_dev *d = NULL;
2135 /* FIXME: we will probably need more device IDs here... */
2136 d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
2137 if (d != NULL) {
2138 bcm->irq = d->irq;
2139 }
2140 }
2141#endif
2142 res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
2143 SA_SHIRQ, KBUILD_MODNAME, bcm);
2144 if (res) {
2145 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
2146 return -ENODEV;
2147 }
2148 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2149 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2150 i = 0;
2151 while (1) {
2152 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2153 if (data == BCM43xx_IRQ_READY)
2154 break;
2155 i++;
2156 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2157 printk(KERN_ERR PFX "Card IRQ register not responding. "
2158 "Giving up.\n");
2159 free_irq(bcm->irq, bcm);
2160 return -ENODEV;
2161 }
2162 udelay(10);
2163 }
2164 // dummy read
2165 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2166
2167 return 0;
2168}
2169
2170/* Switch to the core used to write the GPIO register.
2171 * This is either the ChipCommon, or the PCI core.
2172 */
2173static int switch_to_gpio_core(struct bcm43xx_private *bcm)
2174{
2175 int err;
2176
2177 /* Where to find the GPIO register depends on the chipset.
2178 * If it has a ChipCommon, its register at offset 0x6c is the GPIO
2179 * control register. Otherwise the register at offset 0x6c in the
2180 * PCI core is the GPIO control register.
2181 */
2182 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
2183 if (err == -ENODEV) {
2184 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2185 if (unlikely(err == -ENODEV)) {
2186 printk(KERN_ERR PFX "gpio error: "
2187 "Neither ChipCommon nor PCI core available!\n");
2188 }
2189 }
2190
2191 return err;
2192}
2193
2194/* Initialize the GPIOs
2195 * http://bcm-specs.sipsolutions.net/GPIO
2196 */
2197static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
2198{
2199 struct bcm43xx_coreinfo *old_core;
2200 int err;
2201 u32 mask, set;
2202
2203 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2204 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2205 & 0xFFFF3FFF);
2206
2207 bcm43xx_leds_switch_all(bcm, 0);
2208 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2209 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
2210
2211 mask = 0x0000001F;
2212 set = 0x0000000F;
2213 if (bcm->chip_id == 0x4301) {
2214 mask |= 0x0060;
2215 set |= 0x0060;
2216 }
2217 if (0 /* FIXME: conditional unknown */) {
2218 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2219 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2220 | 0x0100);
2221 mask |= 0x0180;
2222 set |= 0x0180;
2223 }
2224 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
2225 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
2226 bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
2227 | 0x0200);
2228 mask |= 0x0200;
2229 set |= 0x0200;
2230 }
2231 if (bcm->current_core->rev >= 2)
2232 mask |= 0x0010; /* FIXME: This is redundant. */
2233
2234 old_core = bcm->current_core;
2235 err = switch_to_gpio_core(bcm);
2236 if (err)
2237 goto out;
2238 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
2239 (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);
2240 err = bcm43xx_switch_core(bcm, old_core);
2241out:
2242 return err;
2243}
2244
2245/* Turn off all GPIO stuff. Call this on module unload, for example. */
2246static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
2247{
2248 struct bcm43xx_coreinfo *old_core;
2249 int err;
2250
2251 old_core = bcm->current_core;
2252 err = switch_to_gpio_core(bcm);
2253 if (err)
2254 return err;
2255 bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);
2256 err = bcm43xx_switch_core(bcm, old_core);
2257 assert(err == 0);
2258
2259 return 0;
2260}
2261
2262/* http://bcm-specs.sipsolutions.net/EnableMac */
2263void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
2264{
2265 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2266 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2267 | BCM43xx_SBF_MAC_ENABLED);
2268 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
2269 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
2270 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2271 bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
2272}
2273
2274/* http://bcm-specs.sipsolutions.net/SuspendMAC */
2275void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
2276{
2277 int i;
2278 u32 tmp;
2279
2280 bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
2281 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2282 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
2283 & ~BCM43xx_SBF_MAC_ENABLED);
2284 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2285 for (i = 100000; i; i--) {
2286 tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2287 if (tmp & BCM43xx_IRQ_READY)
2288 return;
2289 udelay(10);
2290 }
2291 printkl(KERN_ERR PFX "MAC suspend failed\n");
2292}
2293
2294void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
2295 int iw_mode)
2296{
2297 unsigned long flags;
2298 struct net_device *net_dev = bcm->net_dev;
2299 u32 status;
2300 u16 value;
2301
2302 spin_lock_irqsave(&bcm->ieee->lock, flags);
2303 bcm->ieee->iw_mode = iw_mode;
2304 spin_unlock_irqrestore(&bcm->ieee->lock, flags);
2305 if (iw_mode == IW_MODE_MONITOR)
2306 net_dev->type = ARPHRD_IEEE80211;
2307 else
2308 net_dev->type = ARPHRD_ETHER;
2309
2310 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2311 /* Reset status to infrastructured mode */
2312 status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
2313 status &= ~BCM43xx_SBF_MODE_PROMISC;
2314 status |= BCM43xx_SBF_MODE_NOTADHOC;
2315
2316/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */
2317status |= BCM43xx_SBF_MODE_PROMISC;
2318
2319 switch (iw_mode) {
2320 case IW_MODE_MONITOR:
2321 status |= BCM43xx_SBF_MODE_MONITOR;
2322 status |= BCM43xx_SBF_MODE_PROMISC;
2323 break;
2324 case IW_MODE_ADHOC:
2325 status &= ~BCM43xx_SBF_MODE_NOTADHOC;
2326 break;
2327 case IW_MODE_MASTER:
2328 status |= BCM43xx_SBF_MODE_AP;
2329 break;
2330 case IW_MODE_SECOND:
2331 case IW_MODE_REPEAT:
2332 TODO(); /* TODO */
2333 break;
2334 case IW_MODE_INFRA:
2335 /* nothing to be done here... */
2336 break;
2337 default:
2338 dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);
2339 }
2340 if (net_dev->flags & IFF_PROMISC)
2341 status |= BCM43xx_SBF_MODE_PROMISC;
2342 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
2343
2344 value = 0x0002;
2345 if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
2346 if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
2347 value = 0x0064;
2348 else
2349 value = 0x0032;
2350 }
2351 bcm43xx_write16(bcm, 0x0612, value);
2352}
2353
2354/* This is the opposite of bcm43xx_chip_init() */
2355static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2356{
2357 bcm43xx_radio_turn_off(bcm);
2358 if (!modparam_noleds)
2359 bcm43xx_leds_exit(bcm);
2360 bcm43xx_gpio_cleanup(bcm);
2361 free_irq(bcm->irq, bcm);
2362 bcm43xx_release_firmware(bcm, 0);
2363}
2364
2365/* Initialize the chip
2366 * http://bcm-specs.sipsolutions.net/ChipInit
2367 */
2368static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2369{
2370 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
2371 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2372 int err;
2373 int tmp;
2374 u32 value32;
2375 u16 value16;
2376
2377 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
2378 BCM43xx_SBF_CORE_READY
2379 | BCM43xx_SBF_400);
2380
2381 err = bcm43xx_request_firmware(bcm);
2382 if (err)
2383 goto out;
2384 bcm43xx_upload_microcode(bcm);
2385
2386 err = bcm43xx_initialize_irq(bcm);
2387 if (err)
2388 goto err_release_fw;
2389
2390 err = bcm43xx_gpio_init(bcm);
2391 if (err)
2392 goto err_free_irq;
2393
2394 err = bcm43xx_upload_initvals(bcm);
2395 if (err)
2396 goto err_gpio_cleanup;
2397 bcm43xx_radio_turn_on(bcm);
2398
2399 bcm43xx_write16(bcm, 0x03E6, 0x0000);
2400 err = bcm43xx_phy_init(bcm);
2401 if (err)
2402 goto err_radio_off;
2403
2404 /* Select initial Interference Mitigation. */
2405 tmp = radio->interfmode;
2406 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2407 bcm43xx_radio_set_interference_mitigation(bcm, tmp);
2408
2409 bcm43xx_phy_set_antenna_diversity(bcm);
2410 bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT);
2411 if (phy->type == BCM43xx_PHYTYPE_B) {
2412 value16 = bcm43xx_read16(bcm, 0x005E);
2413 value16 |= 0x0004;
2414 bcm43xx_write16(bcm, 0x005E, value16);
2415 }
2416 bcm43xx_write32(bcm, 0x0100, 0x01000000);
2417 if (bcm->current_core->rev < 5)
2418 bcm43xx_write32(bcm, 0x010C, 0x01000000);
2419
2420 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2421 value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC;
2422 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2423 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2424 value32 |= BCM43xx_SBF_MODE_NOTADHOC;
2425 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2426
2427 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2428 value32 |= 0x100000;
2429 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
2430
2431 if (bcm43xx_using_pio(bcm)) {
2432 bcm43xx_write32(bcm, 0x0210, 0x00000100);
2433 bcm43xx_write32(bcm, 0x0230, 0x00000100);
2434 bcm43xx_write32(bcm, 0x0250, 0x00000100);
2435 bcm43xx_write32(bcm, 0x0270, 0x00000100);
2436 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000);
2437 }
2438
2439 /* Probe Response Timeout value */
2440 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2441 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
2442
2443 /* Initially set the wireless operation mode. */
2444 bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode);
2445
2446 if (bcm->current_core->rev < 3) {
2447 bcm43xx_write16(bcm, 0x060E, 0x0000);
2448 bcm43xx_write16(bcm, 0x0610, 0x8000);
2449 bcm43xx_write16(bcm, 0x0604, 0x0000);
2450 bcm43xx_write16(bcm, 0x0606, 0x0200);
2451 } else {
2452 bcm43xx_write32(bcm, 0x0188, 0x80000000);
2453 bcm43xx_write32(bcm, 0x018C, 0x02000000);
2454 }
2455 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
2456 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
2457 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2458 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
2459 bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
2460
2461 value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
2462 value32 |= 0x00100000;
2463 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32);
2464
2465 bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm));
2466
2467 assert(err == 0);
2468 dprintk(KERN_INFO PFX "Chip initialized\n");
2469out:
2470 return err;
2471
2472err_radio_off:
2473 bcm43xx_radio_turn_off(bcm);
2474err_gpio_cleanup:
2475 bcm43xx_gpio_cleanup(bcm);
2476err_free_irq:
2477 free_irq(bcm->irq, bcm);
2478err_release_fw:
2479 bcm43xx_release_firmware(bcm, 1);
2480 goto out;
2481}
2482
2483/* Validate chip access
2484 * http://bcm-specs.sipsolutions.net/ValidateChipAccess */
2485static int bcm43xx_validate_chip(struct bcm43xx_private *bcm)
2486{
2487 u32 value;
2488 u32 shm_backup;
2489
2490 shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000);
2491 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA);
2492 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA)
2493 goto error;
2494 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55);
2495 if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55)
2496 goto error;
2497 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup);
2498
2499 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
2500 if ((value | 0x80000000) != 0x80000400)
2501 goto error;
2502
2503 value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2504 if (value != 0x00000000)
2505 goto error;
2506
2507 return 0;
2508error:
2509 printk(KERN_ERR PFX "Failed to validate the chipaccess\n");
2510 return -ENODEV;
2511}
2512
2513static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
2514{
2515 /* Initialize a "phyinfo" structure. The structure is already
2516 * zeroed out.
2517 */
2518 phy->antenna_diversity = 0xFFFF;
2519 phy->savedpctlreg = 0xFFFF;
2520 phy->minlowsig[0] = 0xFFFF;
2521 phy->minlowsig[1] = 0xFFFF;
2522 spin_lock_init(&phy->lock);
2523}
2524
2525static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
2526{
2527 /* Initialize a "radioinfo" structure. The structure is already
2528 * zeroed out.
2529 */
2530 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2531 radio->channel = 0xFF;
2532 radio->initial_channel = 0xFF;
2533 radio->lofcal = 0xFFFF;
2534 radio->initval = 0xFFFF;
2535 radio->nrssi[0] = -1000;
2536 radio->nrssi[1] = -1000;
2537}
2538
2539static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2540{
2541 int err, i;
2542 int current_core;
2543 u32 core_vendor, core_id, core_rev;
2544 u32 sb_id_hi, chip_id_32 = 0;
2545 u16 pci_device, chip_id_16;
2546 u8 core_count;
2547
2548 memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo));
2549 memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo));
2550 memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo)
2551 * BCM43xx_MAX_80211_CORES);
2552 memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
2553 * BCM43xx_MAX_80211_CORES);
2554 bcm->current_80211_core_idx = -1;
2555 bcm->nr_80211_available = 0;
2556 bcm->current_core = NULL;
2557 bcm->active_80211_core = NULL;
2558
2559 /* map core 0 */
2560 err = _switch_core(bcm, 0);
2561 if (err)
2562 goto out;
2563
2564 /* fetch sb_id_hi from core information registers */
2565 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2566
2567 core_id = (sb_id_hi & 0xFFF0) >> 4;
2568 core_rev = (sb_id_hi & 0xF);
2569 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2570
2571 /* if present, chipcommon is always core 0; read the chipid from it */
2572 if (core_id == BCM43xx_COREID_CHIPCOMMON) {
2573 chip_id_32 = bcm43xx_read32(bcm, 0);
2574 chip_id_16 = chip_id_32 & 0xFFFF;
2575 bcm->core_chipcommon.available = 1;
2576 bcm->core_chipcommon.id = core_id;
2577 bcm->core_chipcommon.rev = core_rev;
2578 bcm->core_chipcommon.index = 0;
2579 /* While we are at it, also read the capabilities. */
2580 bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES);
2581 } else {
2582 /* without a chipCommon, use a hard coded table. */
2583 pci_device = bcm->pci_dev->device;
2584 if (pci_device == 0x4301)
2585 chip_id_16 = 0x4301;
2586 else if ((pci_device >= 0x4305) && (pci_device <= 0x4307))
2587 chip_id_16 = 0x4307;
2588 else if ((pci_device >= 0x4402) && (pci_device <= 0x4403))
2589 chip_id_16 = 0x4402;
2590 else if ((pci_device >= 0x4610) && (pci_device <= 0x4615))
2591 chip_id_16 = 0x4610;
2592 else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
2593 chip_id_16 = 0x4710;
2594#ifdef CONFIG_BCM947XX
2595 else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
2596 chip_id_16 = 0x4309;
2597#endif
2598 else {
2599 printk(KERN_ERR PFX "Could not determine Chip ID\n");
2600 return -ENODEV;
2601 }
2602 }
2603
2604 /* ChipCommon with Core Rev >=4 encodes number of cores,
2605 * otherwise consult hardcoded table */
2606 if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) {
2607 core_count = (chip_id_32 & 0x0F000000) >> 24;
2608 } else {
2609 switch (chip_id_16) {
2610 case 0x4610:
2611 case 0x4704:
2612 case 0x4710:
2613 core_count = 9;
2614 break;
2615 case 0x4310:
2616 core_count = 8;
2617 break;
2618 case 0x5365:
2619 core_count = 7;
2620 break;
2621 case 0x4306:
2622 core_count = 6;
2623 break;
2624 case 0x4301:
2625 case 0x4307:
2626 core_count = 5;
2627 break;
2628 case 0x4402:
2629 core_count = 3;
2630 break;
2631 default:
2632 /* SOL if we get here */
2633 assert(0);
2634 core_count = 1;
2635 }
2636 }
2637
2638 bcm->chip_id = chip_id_16;
2639 bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16;
2640 bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20;
2641
2642 dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
2643 bcm->chip_id, bcm->chip_rev);
2644 dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
2645 if (bcm->core_chipcommon.available) {
2646 dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2647 core_id, core_rev, core_vendor,
2648 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
2649 }
2650
2651 if (bcm->core_chipcommon.available)
2652 current_core = 1;
2653 else
2654 current_core = 0;
2655 for ( ; current_core < core_count; current_core++) {
2656 struct bcm43xx_coreinfo *core;
2657 struct bcm43xx_coreinfo_80211 *ext_80211;
2658
2659 err = _switch_core(bcm, current_core);
2660 if (err)
2661 goto out;
2662 /* Gather information */
2663 /* fetch sb_id_hi from core information registers */
2664 sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
2665
2666 /* extract core_id, core_rev, core_vendor */
2667 core_id = (sb_id_hi & 0xFFF0) >> 4;
2668 core_rev = (sb_id_hi & 0xF);
2669 core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
2670
2671 dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
2672 current_core, core_id, core_rev, core_vendor,
2673 bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
2674
2675 core = NULL;
2676 switch (core_id) {
2677 case BCM43xx_COREID_PCI:
2678 core = &bcm->core_pci;
2679 if (core->available) {
2680 printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
2681 continue;
2682 }
2683 break;
2684 case BCM43xx_COREID_80211:
2685 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
2686 core = &(bcm->core_80211[i]);
2687 ext_80211 = &(bcm->core_80211_ext[i]);
2688 if (!core->available)
2689 break;
2690 core = NULL;
2691 }
2692 if (!core) {
2693 printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n",
2694 BCM43xx_MAX_80211_CORES);
2695 continue;
2696 }
2697 if (i != 0) {
2698 /* More than one 80211 core is only supported
2699 * by special chips.
2700 * There are chips with two 80211 cores, but with
2701 * dangling pins on the second core. Be careful
2702 * and ignore these cores here.
2703 */
2704 if (bcm->pci_dev->device != 0x4324) {
2705 dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
2706 continue;
2707 }
2708 }
2709 switch (core_rev) {
2710 case 2:
2711 case 4:
2712 case 5:
2713 case 6:
2714 case 7:
2715 case 9:
2716 break;
2717 default:
2718 printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
2719 core_rev);
2720 err = -ENODEV;
2721 goto out;
2722 }
2723 bcm->nr_80211_available++;
2724 bcm43xx_init_struct_phyinfo(&ext_80211->phy);
2725 bcm43xx_init_struct_radioinfo(&ext_80211->radio);
2726 break;
2727 case BCM43xx_COREID_CHIPCOMMON:
2728 printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n");
2729 break;
2730 }
2731 if (core) {
2732 core->available = 1;
2733 core->id = core_id;
2734 core->rev = core_rev;
2735 core->index = current_core;
2736 }
2737 }
2738
2739 if (!bcm->core_80211[0].available) {
2740 printk(KERN_ERR PFX "Error: No 80211 core found!\n");
2741 err = -ENODEV;
2742 goto out;
2743 }
2744
2745 err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
2746
2747 assert(err == 0);
2748out:
2749 return err;
2750}
2751
2752static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm)
2753{
2754 const u8 *mac = (const u8*)(bcm->net_dev->dev_addr);
2755 u8 *bssid = bcm->ieee->bssid;
2756
2757 switch (bcm->ieee->iw_mode) {
2758 case IW_MODE_ADHOC:
2759 random_ether_addr(bssid);
2760 break;
2761 case IW_MODE_MASTER:
2762 case IW_MODE_INFRA:
2763 case IW_MODE_REPEAT:
2764 case IW_MODE_SECOND:
2765 case IW_MODE_MONITOR:
2766 memcpy(bssid, mac, ETH_ALEN);
2767 break;
2768 default:
2769 assert(0);
2770 }
2771}
2772
2773static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm,
2774 u16 rate,
2775 int is_ofdm)
2776{
2777 u16 offset;
2778
2779 if (is_ofdm) {
2780 offset = 0x480;
2781 offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
2782 }
2783 else {
2784 offset = 0x4C0;
2785 offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
2786 }
2787 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20,
2788 bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset));
2789}
2790
2791static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm)
2792{
2793 switch (bcm43xx_current_phy(bcm)->type) {
2794 case BCM43xx_PHYTYPE_A:
2795 case BCM43xx_PHYTYPE_G:
2796 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1);
2797 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1);
2798 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1);
2799 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1);
2800 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1);
2801 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1);
2802 bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1);
2803 case BCM43xx_PHYTYPE_B:
2804 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0);
2805 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0);
2806 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0);
2807 bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0);
2808 break;
2809 default:
2810 assert(0);
2811 }
2812}
2813
2814static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2815{
2816 bcm43xx_chip_cleanup(bcm);
2817 bcm43xx_pio_free(bcm);
2818 bcm43xx_dma_free(bcm);
2819
2820 bcm->current_core->initialized = 0;
2821}
2822
2823/* http://bcm-specs.sipsolutions.net/80211Init */
2824static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2825{
2826 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2827 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
2828 u32 ucodeflags;
2829 int err;
2830 u32 sbimconfiglow;
2831 u8 limit;
2832
2833 if (bcm->chip_rev < 5) {
2834 sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
2835 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
2836 sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
2837 if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
2838 sbimconfiglow |= 0x32;
2839 else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
2840 sbimconfiglow |= 0x53;
2841 else
2842 assert(0);
2843 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
2844 }
2845
2846 bcm43xx_phy_calibrate(bcm);
2847 err = bcm43xx_chip_init(bcm);
2848 if (err)
2849 goto out;
2850
2851 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev);
2852 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET);
2853
2854 if (0 /*FIXME: which condition has to be used here? */)
2855 ucodeflags |= 0x00000010;
2856
2857 /* HW decryption needs to be set now */
2858 ucodeflags |= 0x40000000;
2859
2860 if (phy->type == BCM43xx_PHYTYPE_G) {
2861 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2862 if (phy->rev == 1)
2863 ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY;
2864 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
2865 ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL;
2866 } else if (phy->type == BCM43xx_PHYTYPE_B) {
2867 ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY;
2868 if (phy->rev >= 2 && radio->version == 0x2050)
2869 ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY;
2870 }
2871
2872 if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2873 BCM43xx_UCODEFLAGS_OFFSET)) {
2874 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2875 BCM43xx_UCODEFLAGS_OFFSET, ucodeflags);
2876 }
2877
2878 /* Short/Long Retry Limit.
2879 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
2880 * the chip-internal counter.
2881 */
2882 limit = limit_value(modparam_short_retry, 0, 0xF);
2883 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit);
2884 limit = limit_value(modparam_long_retry, 0, 0xF);
2885 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit);
2886
2887 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3);
2888 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2);
2889
2890 bcm43xx_rate_memory_init(bcm);
2891
2892 /* Minimum Contention Window */
2893 if (phy->type == BCM43xx_PHYTYPE_B)
2894 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f);
2895 else
2896 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f);
2897 /* Maximum Contention Window */
2898 bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
2899
2900 bcm43xx_gen_bssid(bcm);
2901 bcm43xx_write_mac_bssid_templates(bcm);
2902
2903 if (bcm->current_core->rev >= 5)
2904 bcm43xx_write16(bcm, 0x043C, 0x000C);
2905
2906 if (bcm43xx_using_pio(bcm))
2907 err = bcm43xx_pio_init(bcm);
2908 else
2909 err = bcm43xx_dma_init(bcm);
2910 if (err)
2911 goto err_chip_cleanup;
2912 bcm43xx_write16(bcm, 0x0612, 0x0050);
2913 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2914 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2915
2916 bcm43xx_mac_enable(bcm);
2917 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
2918
2919 bcm->current_core->initialized = 1;
2920out:
2921 return err;
2922
2923err_chip_cleanup:
2924 bcm43xx_chip_cleanup(bcm);
2925 goto out;
2926}
2927
2928static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
2929{
2930 int err;
2931 u16 pci_status;
2932
2933 err = bcm43xx_pctl_set_crystal(bcm, 1);
2934 if (err)
2935 goto out;
2936 bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
2937 bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
2938
2939out:
2940 return err;
2941}
2942
2943static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm)
2944{
2945 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
2946 bcm43xx_pctl_set_crystal(bcm, 0);
2947}
2948
2949static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm,
2950 u32 address,
2951 u32 data)
2952{
2953 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address);
2954 bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data);
2955}
2956
2957static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
2958{
2959 int err;
2960 struct bcm43xx_coreinfo *old_core;
2961
2962 old_core = bcm->current_core;
2963 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2964 if (err)
2965 goto out;
2966
2967 bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
2968
2969 bcm43xx_switch_core(bcm, old_core);
2970 assert(err == 0);
2971out:
2972 return err;
2973}
2974
2975/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
2976 * To enable core 0, pass a core_mask of 1<<0
2977 */
2978static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
2979 u32 core_mask)
2980{
2981 u32 backplane_flag_nr;
2982 u32 value;
2983 struct bcm43xx_coreinfo *old_core;
2984 int err = 0;
2985
2986 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG);
2987 backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK;
2988
2989 old_core = bcm->current_core;
2990 err = bcm43xx_switch_core(bcm, &bcm->core_pci);
2991 if (err)
2992 goto out;
2993
2994 if (bcm->core_pci.rev < 6) {
2995 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
2996 value |= (1 << backplane_flag_nr);
2997 bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
2998 } else {
2999 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value);
3000 if (err) {
3001 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3002 goto out_switch_back;
3003 }
3004 value |= core_mask << 8;
3005 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value);
3006 if (err) {
3007 printk(KERN_ERR PFX "Error: ICR setup failure!\n");
3008 goto out_switch_back;
3009 }
3010 }
3011
3012 value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
3013 value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
3014 bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
3015
3016 if (bcm->core_pci.rev < 5) {
3017 value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
3018 value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
3019 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
3020 value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
3021 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
3022 bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
3023 err = bcm43xx_pcicore_commit_settings(bcm);
3024 assert(err == 0);
3025 }
3026
3027out_switch_back:
3028 err = bcm43xx_switch_core(bcm, old_core);
3029out:
3030 return err;
3031}
3032
3033static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3034{
3035 ieee80211softmac_start(bcm->net_dev);
3036}
3037
3038static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
3039{
3040 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
3041
3042 if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2)
3043 return;
3044
3045 bcm43xx_mac_suspend(bcm);
3046 bcm43xx_phy_lo_g_measure(bcm);
3047 bcm43xx_mac_enable(bcm);
3048}
3049
3050static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm)
3051{
3052 bcm43xx_phy_lo_mark_all_unused(bcm);
3053 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3054 bcm43xx_mac_suspend(bcm);
3055 bcm43xx_calc_nrssi_slope(bcm);
3056 bcm43xx_mac_enable(bcm);
3057 }
3058}
3059
3060static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
3061{
3062 /* Update device statistics. */
3063 bcm43xx_calculate_link_quality(bcm);
3064}
3065
3066static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
3067{
3068 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
3069 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
3070
3071 if (phy->type == BCM43xx_PHYTYPE_G) {
3072 //TODO: update_aci_moving_average
3073 if (radio->aci_enable && radio->aci_wlan_automatic) {
3074 bcm43xx_mac_suspend(bcm);
3075 if (!radio->aci_enable && 1 /*TODO: not scanning? */) {
3076 if (0 /*TODO: bunch of conditions*/) {
3077 bcm43xx_radio_set_interference_mitigation(bcm,
3078 BCM43xx_RADIO_INTERFMODE_MANUALWLAN);
3079 }
3080 } else if (1/*TODO*/) {
3081 /*
3082 if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) {
3083 bcm43xx_radio_set_interference_mitigation(bcm,
3084 BCM43xx_RADIO_INTERFMODE_NONE);
3085 }
3086 */
3087 }
3088 bcm43xx_mac_enable(bcm);
3089 } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN &&
3090 phy->rev == 1) {
3091 //TODO: implement rev1 workaround
3092 }
3093 }
3094 bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
3095 //TODO for APHY (temperature?)
3096}
3097
3098static void bcm43xx_periodic_task_handler(unsigned long d)
3099{
3100 struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
3101 unsigned long flags;
3102 unsigned int state;
3103
3104 bcm43xx_lock_mmio(bcm, flags);
3105
3106 assert(bcm->initialized);
3107 state = bcm->periodic_state;
3108 if (state % 8 == 0)
3109 bcm43xx_periodic_every120sec(bcm);
3110 if (state % 4 == 0)
3111 bcm43xx_periodic_every60sec(bcm);
3112 if (state % 2 == 0)
3113 bcm43xx_periodic_every30sec(bcm);
3114 bcm43xx_periodic_every15sec(bcm);
3115 bcm->periodic_state = state + 1;
3116
3117 mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
3118
3119 bcm43xx_unlock_mmio(bcm, flags);
3120}
3121
3122static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
3123{
3124 del_timer_sync(&bcm->periodic_tasks);
3125}
3126
3127static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
3128{
3129 struct timer_list *timer = &(bcm->periodic_tasks);
3130
3131 assert(bcm->initialized);
3132 setup_timer(timer,
3133 bcm43xx_periodic_task_handler,
3134 (unsigned long)bcm);
3135 timer->expires = jiffies;
3136 add_timer(timer);
3137}
3138
3139static void bcm43xx_security_init(struct bcm43xx_private *bcm)
3140{
3141 bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
3142 0x0056) * 2;
3143 bcm43xx_clear_keys(bcm);
3144}
3145
3146/* This is the opposite of bcm43xx_init_board() */
3147static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3148{
3149 int i, err;
3150 unsigned long flags;
3151
3152 bcm43xx_sysfs_unregister(bcm);
3153
3154 bcm43xx_periodic_tasks_delete(bcm);
3155
3156 bcm43xx_lock(bcm, flags);
3157 bcm->initialized = 0;
3158 bcm->shutting_down = 1;
3159 bcm43xx_unlock(bcm, flags);
3160
3161 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3162 if (!bcm->core_80211[i].available)
3163 continue;
3164 if (!bcm->core_80211[i].initialized)
3165 continue;
3166
3167 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3168 assert(err == 0);
3169 bcm43xx_wireless_core_cleanup(bcm);
3170 }
3171
3172 bcm43xx_pctl_set_crystal(bcm, 0);
3173
3174 bcm43xx_lock(bcm, flags);
3175 bcm->shutting_down = 0;
3176 bcm43xx_unlock(bcm, flags);
3177}
3178
3179static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3180{
3181 int i, err;
3182 int connect_phy;
3183 unsigned long flags;
3184
3185 might_sleep();
3186
3187 bcm43xx_lock(bcm, flags);
3188 bcm->initialized = 0;
3189 bcm->shutting_down = 0;
3190 bcm43xx_unlock(bcm, flags);
3191
3192 err = bcm43xx_pctl_set_crystal(bcm, 1);
3193 if (err)
3194 goto out;
3195 err = bcm43xx_pctl_init(bcm);
3196 if (err)
3197 goto err_crystal_off;
3198 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3199 if (err)
3200 goto err_crystal_off;
3201
3202 tasklet_enable(&bcm->isr_tasklet);
3203 for (i = 0; i < bcm->nr_80211_available; i++) {
3204 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3205 assert(err != -ENODEV);
3206 if (err)
3207 goto err_80211_unwind;
3208
3209 /* Enable the selected wireless core.
3210 * Connect PHY only on the first core.
3211 */
3212 if (!bcm43xx_core_enabled(bcm)) {
3213 if (bcm->nr_80211_available == 1) {
3214 connect_phy = bcm43xx_current_phy(bcm)->connected;
3215 } else {
3216 if (i == 0)
3217 connect_phy = 1;
3218 else
3219 connect_phy = 0;
3220 }
3221 bcm43xx_wireless_core_reset(bcm, connect_phy);
3222 }
3223
3224 if (i != 0)
3225 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
3226
3227 err = bcm43xx_wireless_core_init(bcm);
3228 if (err)
3229 goto err_80211_unwind;
3230
3231 if (i != 0) {
3232 bcm43xx_mac_suspend(bcm);
3233 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3234 bcm43xx_radio_turn_off(bcm);
3235 }
3236 }
3237 bcm->active_80211_core = &bcm->core_80211[0];
3238 if (bcm->nr_80211_available >= 2) {
3239 bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
3240 bcm43xx_mac_enable(bcm);
3241 }
3242 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3243 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3244 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3245 bcm43xx_security_init(bcm);
3246 bcm43xx_softmac_init(bcm);
3247
3248 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3249
3250 if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
3251 bcm43xx_mac_suspend(bcm);
3252 bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
3253 bcm43xx_mac_enable(bcm);
3254 }
3255
3256 /* Initialization of the board is done. Flag it as such. */
3257 bcm43xx_lock(bcm, flags);
3258 bcm->initialized = 1;
3259 bcm43xx_unlock(bcm, flags);
3260
3261 bcm43xx_periodic_tasks_setup(bcm);
3262 bcm43xx_sysfs_register(bcm);
3263 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
3264
3265 assert(err == 0);
3266out:
3267 return err;
3268
3269err_80211_unwind:
3270 tasklet_disable(&bcm->isr_tasklet);
3271 /* unwind all 80211 initialization */
3272 for (i = 0; i < bcm->nr_80211_available; i++) {
3273 if (!bcm->core_80211[i].initialized)
3274 continue;
3275 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3276 bcm43xx_wireless_core_cleanup(bcm);
3277 }
3278err_crystal_off:
3279 bcm43xx_pctl_set_crystal(bcm, 0);
3280 goto out;
3281}
3282
3283static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
3284{
3285 struct pci_dev *pci_dev = bcm->pci_dev;
3286 int i;
3287
3288 bcm43xx_chipset_detach(bcm);
3289 /* Do _not_ access the chip, after it is detached. */
3290 iounmap(bcm->mmio_addr);
3291
3292 pci_release_regions(pci_dev);
3293 pci_disable_device(pci_dev);
3294
3295 /* Free allocated structures/fields */
3296 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3297 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3298 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3299 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
3300 }
3301}
3302
3303static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
3304{
3305 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
3306 u16 value;
3307 u8 phy_version;
3308 u8 phy_type;
3309 u8 phy_rev;
3310 int phy_rev_ok = 1;
3311 void *p;
3312
3313 value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
3314
3315 phy_version = (value & 0xF000) >> 12;
3316 phy_type = (value & 0x0F00) >> 8;
3317 phy_rev = (value & 0x000F);
3318
3319 dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
3320 phy_version, phy_type, phy_rev);
3321
3322 switch (phy_type) {
3323 case BCM43xx_PHYTYPE_A:
3324 if (phy_rev >= 4)
3325 phy_rev_ok = 0;
3326 /*FIXME: We need to switch the ieee->modulation, etc.. flags,
3327 * if we switch 80211 cores after init is done.
3328 * As we do not implement on the fly switching between
3329 * wireless cores, I will leave this as a future task.
3330 */
3331 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION;
3332 bcm->ieee->mode = IEEE_A;
3333 bcm->ieee->freq_band = IEEE80211_52GHZ_BAND |
3334 IEEE80211_24GHZ_BAND;
3335 break;
3336 case BCM43xx_PHYTYPE_B:
3337 if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7)
3338 phy_rev_ok = 0;
3339 bcm->ieee->modulation = IEEE80211_CCK_MODULATION;
3340 bcm->ieee->mode = IEEE_B;
3341 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3342 break;
3343 case BCM43xx_PHYTYPE_G:
3344 if (phy_rev > 7)
3345 phy_rev_ok = 0;
3346 bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
3347 IEEE80211_CCK_MODULATION;
3348 bcm->ieee->mode = IEEE_G;
3349 bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
3350 break;
3351 default:
3352 printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n",
3353 phy_type);
3354 return -ENODEV;
3355 };
3356 if (!phy_rev_ok) {
3357 printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
3358 phy_rev);
3359 }
3360
3361 phy->version = phy_version;
3362 phy->type = phy_type;
3363 phy->rev = phy_rev;
3364 if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
3365 p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT,
3366 GFP_KERNEL);
3367 if (!p)
3368 return -ENOMEM;
3369 phy->_lo_pairs = p;
3370 }
3371
3372 return 0;
3373}
3374
3375static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
3376{
3377 struct pci_dev *pci_dev = bcm->pci_dev;
3378 struct net_device *net_dev = bcm->net_dev;
3379 int err;
3380 int i;
3381 unsigned long mmio_start, mmio_flags, mmio_len;
3382 u32 coremask;
3383
3384 err = pci_enable_device(pci_dev);
3385 if (err) {
3386 printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
3387 goto out;
3388 }
3389 mmio_start = pci_resource_start(pci_dev, 0);
3390 mmio_flags = pci_resource_flags(pci_dev, 0);
3391 mmio_len = pci_resource_len(pci_dev, 0);
3392 if (!(mmio_flags & IORESOURCE_MEM)) {
3393 printk(KERN_ERR PFX
3394 "%s, region #0 not an MMIO resource, aborting\n",
3395 pci_name(pci_dev));
3396 err = -ENODEV;
3397 goto err_pci_disable;
3398 }
3399 err = pci_request_regions(pci_dev, KBUILD_MODNAME);
3400 if (err) {
3401 printk(KERN_ERR PFX
3402 "could not access PCI resources (%i)\n", err);
3403 goto err_pci_disable;
3404 }
3405 /* enable PCI bus-mastering */
3406 pci_set_master(pci_dev);
3407 bcm->mmio_addr = ioremap(mmio_start, mmio_len);
3408 if (!bcm->mmio_addr) {
3409 printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
3410 pci_name(pci_dev));
3411 err = -EIO;
3412 goto err_pci_release;
3413 }
3414 bcm->mmio_len = mmio_len;
3415 net_dev->base_addr = (unsigned long)bcm->mmio_addr;
3416
3417 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
3418 &bcm->board_vendor);
3419 bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
3420 &bcm->board_type);
3421 bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
3422 &bcm->board_revision);
3423
3424 err = bcm43xx_chipset_attach(bcm);
3425 if (err)
3426 goto err_iounmap;
3427 err = bcm43xx_pctl_init(bcm);
3428 if (err)
3429 goto err_chipset_detach;
3430 err = bcm43xx_probe_cores(bcm);
3431 if (err)
3432 goto err_chipset_detach;
3433
3434 /* Attach all IO cores to the backplane. */
3435 coremask = 0;
3436 for (i = 0; i < bcm->nr_80211_available; i++)
3437 coremask |= (1 << bcm->core_80211[i].index);
3438 //FIXME: Also attach some non80211 cores?
3439 err = bcm43xx_setup_backplane_pci_connection(bcm, coremask);
3440 if (err) {
3441 printk(KERN_ERR PFX "Backplane->PCI connection failed!\n");
3442 goto err_chipset_detach;
3443 }
3444
3445 err = bcm43xx_sprom_extract(bcm);
3446 if (err)
3447 goto err_chipset_detach;
3448 err = bcm43xx_leds_init(bcm);
3449 if (err)
3450 goto err_chipset_detach;
3451
3452 for (i = 0; i < bcm->nr_80211_available; i++) {
3453 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
3454 assert(err != -ENODEV);
3455 if (err)
3456 goto err_80211_unwind;
3457
3458 /* Enable the selected wireless core.
3459 * Connect PHY only on the first core.
3460 */
3461 bcm43xx_wireless_core_reset(bcm, (i == 0));
3462
3463 err = bcm43xx_read_phyinfo(bcm);
3464 if (err && (i == 0))
3465 goto err_80211_unwind;
3466
3467 err = bcm43xx_read_radioinfo(bcm);
3468 if (err && (i == 0))
3469 goto err_80211_unwind;
3470
3471 err = bcm43xx_validate_chip(bcm);
3472 if (err && (i == 0))
3473 goto err_80211_unwind;
3474
3475 bcm43xx_radio_turn_off(bcm);
3476 err = bcm43xx_phy_init_tssi2dbm_table(bcm);
3477 if (err)
3478 goto err_80211_unwind;
3479 bcm43xx_wireless_core_disable(bcm);
3480 }
3481 bcm43xx_pctl_set_crystal(bcm, 0);
3482
3483 /* Set the MAC address in the networking subsystem */
3484 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
3485 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
3486 else
3487 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
3488
3489 bcm43xx_geo_init(bcm);
3490
3491 snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
3492 "Broadcom %04X", bcm->chip_id);
3493
3494 assert(err == 0);
3495out:
3496 return err;
3497
3498err_80211_unwind:
3499 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3500 kfree(bcm->core_80211_ext[i].phy._lo_pairs);
3501 if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl)
3502 kfree(bcm->core_80211_ext[i].phy.tssi2dbm);
3503 }
3504err_chipset_detach:
3505 bcm43xx_chipset_detach(bcm);
3506err_iounmap:
3507 iounmap(bcm->mmio_addr);
3508err_pci_release:
3509 pci_release_regions(pci_dev);
3510err_pci_disable:
3511 pci_disable_device(pci_dev);
3512 goto out;
3513}
3514
3515/* Do the Hardware IO operations to send the txb */
3516static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3517 struct ieee80211_txb *txb)
3518{
3519 int err = -ENODEV;
3520
3521 if (bcm43xx_using_pio(bcm))
3522 err = bcm43xx_pio_tx(bcm, txb);
3523 else
3524 err = bcm43xx_dma_tx(bcm, txb);
3525
3526 return err;
3527}
3528
3529static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
3530 u8 channel)
3531{
3532 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3533 struct bcm43xx_radioinfo *radio;
3534 unsigned long flags;
3535
3536 bcm43xx_lock_mmio(bcm, flags);
3537 if (bcm->initialized) {
3538 bcm43xx_mac_suspend(bcm);
3539 bcm43xx_radio_selectchannel(bcm, channel, 0);
3540 bcm43xx_mac_enable(bcm);
3541 } else {
3542 radio = bcm43xx_current_radio(bcm);
3543 radio->initial_channel = channel;
3544 }
3545 bcm43xx_unlock_mmio(bcm, flags);
3546}
3547
3548/* set_security() callback in struct ieee80211_device */
3549static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
3550 struct ieee80211_security *sec)
3551{
3552 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3553 struct ieee80211_security *secinfo = &bcm->ieee->sec;
3554 unsigned long flags;
3555 int keyidx;
3556
3557 dprintk(KERN_INFO PFX "set security called\n");
3558
3559 bcm43xx_lock_mmio(bcm, flags);
3560
3561 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
3562 if (sec->flags & (1<<keyidx)) {
3563 secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
3564 secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
3565 memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
3566 }
3567
3568 if (sec->flags & SEC_ACTIVE_KEY) {
3569 secinfo->active_key = sec->active_key;
3570 dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key);
3571 }
3572 if (sec->flags & SEC_UNICAST_GROUP) {
3573 secinfo->unicast_uses_group = sec->unicast_uses_group;
3574 dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group);
3575 }
3576 if (sec->flags & SEC_LEVEL) {
3577 secinfo->level = sec->level;
3578 dprintk(KERN_INFO PFX " .level = %d\n", sec->level);
3579 }
3580 if (sec->flags & SEC_ENABLED) {
3581 secinfo->enabled = sec->enabled;
3582 dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled);
3583 }
3584 if (sec->flags & SEC_ENCRYPT) {
3585 secinfo->encrypt = sec->encrypt;
3586 dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt);
3587 }
3588 if (bcm->initialized && !bcm->ieee->host_encrypt) {
3589 if (secinfo->enabled) {
3590 /* upload WEP keys to hardware */
3591 char null_address[6] = { 0 };
3592 u8 algorithm = 0;
3593 for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
3594 if (!(sec->flags & (1<<keyidx)))
3595 continue;
3596 switch (sec->encode_alg[keyidx]) {
3597 case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
3598 case SEC_ALG_WEP:
3599 algorithm = BCM43xx_SEC_ALGO_WEP;
3600 if (secinfo->key_sizes[keyidx] == 13)
3601 algorithm = BCM43xx_SEC_ALGO_WEP104;
3602 break;
3603 case SEC_ALG_TKIP:
3604 FIXME();
3605 algorithm = BCM43xx_SEC_ALGO_TKIP;
3606 break;
3607 case SEC_ALG_CCMP:
3608 FIXME();
3609 algorithm = BCM43xx_SEC_ALGO_AES;
3610 break;
3611 default:
3612 assert(0);
3613 break;
3614 }
3615 bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
3616 bcm->key[keyidx].enabled = 1;
3617 bcm->key[keyidx].algorithm = algorithm;
3618 }
3619 } else
3620 bcm43xx_clear_keys(bcm);
3621 }
3622 bcm43xx_unlock_mmio(bcm, flags);
3623}
3624
3625/* hard_start_xmit() callback in struct ieee80211_device */
3626static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
3627 struct net_device *net_dev,
3628 int pri)
3629{
3630 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3631 int err = -ENODEV;
3632 unsigned long flags;
3633
3634 bcm43xx_lock_mmio(bcm, flags);
3635 if (likely(bcm->initialized))
3636 err = bcm43xx_tx(bcm, txb);
3637 bcm43xx_unlock_mmio(bcm, flags);
3638
3639 return err;
3640}
3641
3642static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
3643{
3644 return &(bcm43xx_priv(net_dev)->ieee->stats);
3645}
3646
3647static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
3648{
3649 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3650 unsigned long flags;
3651
3652 bcm43xx_lock_mmio(bcm, flags);
3653 bcm43xx_controller_restart(bcm, "TX timeout");
3654 bcm43xx_unlock_mmio(bcm, flags);
3655}
3656
3657#ifdef CONFIG_NET_POLL_CONTROLLER
3658static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3659{
3660 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3661 unsigned long flags;
3662
3663 local_irq_save(flags);
3664 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3665 local_irq_restore(flags);
3666}
3667#endif /* CONFIG_NET_POLL_CONTROLLER */
3668
3669static int bcm43xx_net_open(struct net_device *net_dev)
3670{
3671 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3672
3673 return bcm43xx_init_board(bcm);
3674}
3675
3676static int bcm43xx_net_stop(struct net_device *net_dev)
3677{
3678 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3679
3680 ieee80211softmac_stop(net_dev);
3681 bcm43xx_disable_interrupts_sync(bcm, NULL);
3682 bcm43xx_free_board(bcm);
3683
3684 return 0;
3685}
3686
3687static int bcm43xx_init_private(struct bcm43xx_private *bcm,
3688 struct net_device *net_dev,
3689 struct pci_dev *pci_dev)
3690{
3691 int err;
3692
3693 bcm->ieee = netdev_priv(net_dev);
3694 bcm->softmac = ieee80211_priv(net_dev);
3695 bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
3696
3697 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3698 bcm->pci_dev = pci_dev;
3699 bcm->net_dev = net_dev;
3700 bcm->bad_frames_preempt = modparam_bad_frames_preempt;
3701 spin_lock_init(&bcm->_lock);
3702 tasklet_init(&bcm->isr_tasklet,
3703 (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
3704 (unsigned long)bcm);
3705 tasklet_disable_nosync(&bcm->isr_tasklet);
3706 if (modparam_pio) {
3707 bcm->__using_pio = 1;
3708 } else {
3709 err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
3710 err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
3711 if (err) {
3712#ifdef CONFIG_BCM43XX_PIO
3713 printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
3714 bcm->__using_pio = 1;
3715#else
3716 printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
3717 "Recompile the driver with PIO support, please.\n");
3718 return -ENODEV;
3719#endif /* CONFIG_BCM43XX_PIO */
3720 }
3721 }
3722 bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
3723
3724 /* default to sw encryption for now */
3725 bcm->ieee->host_build_iv = 0;
3726 bcm->ieee->host_encrypt = 1;
3727 bcm->ieee->host_decrypt = 1;
3728
3729 bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
3730 bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
3731 bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
3732 bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
3733
3734 return 0;
3735}
3736
3737static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
3738 const struct pci_device_id *ent)
3739{
3740 struct net_device *net_dev;
3741 struct bcm43xx_private *bcm;
3742 int err;
3743
3744#ifdef CONFIG_BCM947XX
3745 if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
3746 return -ENODEV;
3747#endif
3748
3749#ifdef DEBUG_SINGLE_DEVICE_ONLY
3750 if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
3751 return -ENODEV;
3752#endif
3753
3754 net_dev = alloc_ieee80211softmac(sizeof(*bcm));
3755 if (!net_dev) {
3756 printk(KERN_ERR PFX
3757 "could not allocate ieee80211 device %s\n",
3758 pci_name(pdev));
3759 err = -ENOMEM;
3760 goto out;
3761 }
3762 /* initialize the net_device struct */
3763 SET_MODULE_OWNER(net_dev);
3764 SET_NETDEV_DEV(net_dev, &pdev->dev);
3765
3766 net_dev->open = bcm43xx_net_open;
3767 net_dev->stop = bcm43xx_net_stop;
3768 net_dev->get_stats = bcm43xx_net_get_stats;
3769 net_dev->tx_timeout = bcm43xx_net_tx_timeout;
3770#ifdef CONFIG_NET_POLL_CONTROLLER
3771 net_dev->poll_controller = bcm43xx_net_poll_controller;
3772#endif
3773 net_dev->wireless_handlers = &bcm43xx_wx_handlers_def;
3774 net_dev->irq = pdev->irq;
3775 SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops);
3776
3777 /* initialize the bcm43xx_private struct */
3778 bcm = bcm43xx_priv(net_dev);
3779 memset(bcm, 0, sizeof(*bcm));
3780 err = bcm43xx_init_private(bcm, net_dev, pdev);
3781 if (err)
3782 goto err_free_netdev;
3783
3784 pci_set_drvdata(pdev, net_dev);
3785
3786 err = bcm43xx_attach_board(bcm);
3787 if (err)
3788 goto err_free_netdev;
3789
3790 err = register_netdev(net_dev);
3791 if (err) {
3792 printk(KERN_ERR PFX "Cannot register net device, "
3793 "aborting.\n");
3794 err = -ENOMEM;
3795 goto err_detach_board;
3796 }
3797
3798 bcm43xx_debugfs_add_device(bcm);
3799
3800 assert(err == 0);
3801out:
3802 return err;
3803
3804err_detach_board:
3805 bcm43xx_detach_board(bcm);
3806err_free_netdev:
3807 free_ieee80211softmac(net_dev);
3808 goto out;
3809}
3810
3811static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3812{
3813 struct net_device *net_dev = pci_get_drvdata(pdev);
3814 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3815
3816 bcm43xx_debugfs_remove_device(bcm);
3817 unregister_netdev(net_dev);
3818 bcm43xx_detach_board(bcm);
3819 assert(bcm->ucode == NULL);
3820 free_ieee80211softmac(net_dev);
3821}
3822
3823/* Hard-reset the chip. Do not call this directly.
3824 * Use bcm43xx_controller_restart()
3825 */
3826static void bcm43xx_chip_reset(void *_bcm)
3827{
3828 struct bcm43xx_private *bcm = _bcm;
3829 struct net_device *net_dev = bcm->net_dev;
3830 struct pci_dev *pci_dev = bcm->pci_dev;
3831 int err;
3832 int was_initialized = bcm->initialized;
3833
3834 netif_stop_queue(bcm->net_dev);
3835 tasklet_disable(&bcm->isr_tasklet);
3836
3837 bcm->firmware_norelease = 1;
3838 if (was_initialized)
3839 bcm43xx_free_board(bcm);
3840 bcm->firmware_norelease = 0;
3841 bcm43xx_detach_board(bcm);
3842 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
3843 if (err)
3844 goto failure;
3845 err = bcm43xx_attach_board(bcm);
3846 if (err)
3847 goto failure;
3848 if (was_initialized) {
3849 err = bcm43xx_init_board(bcm);
3850 if (err)
3851 goto failure;
3852 }
3853 netif_wake_queue(bcm->net_dev);
3854 printk(KERN_INFO PFX "Controller restarted\n");
3855
3856 return;
3857failure:
3858 printk(KERN_ERR PFX "Controller restart failed\n");
3859}
3860
3861/* Hard-reset the chip.
3862 * This can be called from interrupt or process context.
3863 * Make sure to _not_ re-enable device interrupts after this has been called.
3864*/
3865void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
3866{
3867 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3868 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
3869 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
3870 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
3871 schedule_work(&bcm->restart_work);
3872}
3873
3874#ifdef CONFIG_PM
3875
3876static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
3877{
3878 struct net_device *net_dev = pci_get_drvdata(pdev);
3879 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3880 unsigned long flags;
3881 int try_to_shutdown = 0, err;
3882
3883 dprintk(KERN_INFO PFX "Suspending...\n");
3884
3885 bcm43xx_lock(bcm, flags);
3886 bcm->was_initialized = bcm->initialized;
3887 if (bcm->initialized)
3888 try_to_shutdown = 1;
3889 bcm43xx_unlock(bcm, flags);
3890
3891 netif_device_detach(net_dev);
3892 if (try_to_shutdown) {
3893 ieee80211softmac_stop(net_dev);
3894 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
3895 if (unlikely(err)) {
3896 dprintk(KERN_ERR PFX "Suspend failed.\n");
3897 return -EAGAIN;
3898 }
3899 bcm->firmware_norelease = 1;
3900 bcm43xx_free_board(bcm);
3901 bcm->firmware_norelease = 0;
3902 }
3903 bcm43xx_chipset_detach(bcm);
3904
3905 pci_save_state(pdev);
3906 pci_disable_device(pdev);
3907 pci_set_power_state(pdev, pci_choose_state(pdev, state));
3908
3909 dprintk(KERN_INFO PFX "Device suspended.\n");
3910
3911 return 0;
3912}
3913
3914static int bcm43xx_resume(struct pci_dev *pdev)
3915{
3916 struct net_device *net_dev = pci_get_drvdata(pdev);
3917 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
3918 int err = 0;
3919
3920 dprintk(KERN_INFO PFX "Resuming...\n");
3921
3922 pci_set_power_state(pdev, 0);
3923 pci_enable_device(pdev);
3924 pci_restore_state(pdev);
3925
3926 bcm43xx_chipset_attach(bcm);
3927 if (bcm->was_initialized) {
3928 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3929 err = bcm43xx_init_board(bcm);
3930 }
3931 if (err) {
3932 printk(KERN_ERR PFX "Resume failed!\n");
3933 return err;
3934 }
3935
3936 netif_device_attach(net_dev);
3937
3938 /*FIXME: This should be handled by softmac instead. */
3939 schedule_work(&bcm->softmac->associnfo.work);
3940
3941 dprintk(KERN_INFO PFX "Device resumed.\n");
3942
3943 return 0;
3944}
3945
3946#endif /* CONFIG_PM */
3947
3948static struct pci_driver bcm43xx_pci_driver = {
3949 .name = KBUILD_MODNAME,
3950 .id_table = bcm43xx_pci_tbl,
3951 .probe = bcm43xx_init_one,
3952 .remove = __devexit_p(bcm43xx_remove_one),
3953#ifdef CONFIG_PM
3954 .suspend = bcm43xx_suspend,
3955 .resume = bcm43xx_resume,
3956#endif /* CONFIG_PM */
3957};
3958
3959static int __init bcm43xx_init(void)
3960{
3961 printk(KERN_INFO KBUILD_MODNAME " driver\n");
3962 bcm43xx_debugfs_init();
3963 return pci_register_driver(&bcm43xx_pci_driver);
3964}
3965
3966static void __exit bcm43xx_exit(void)
3967{
3968 pci_unregister_driver(&bcm43xx_pci_driver);
3969 bcm43xx_debugfs_exit();
3970}
3971
3972module_init(bcm43xx_init)
3973module_exit(bcm43xx_exit)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
new file mode 100644
index 000000000000..eca79a38594a
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -0,0 +1,168 @@
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#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
56#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
57/* Magic helper macro to pad structures. Ignore those above. It's magic. */
58#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
59
60
61/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
62static inline
63u8 bcm43xx_freq_to_channel_a(int freq)
64{
65 return ((freq - 5000) / 5);
66}
67static inline
68u8 bcm43xx_freq_to_channel_bg(int freq)
69{
70 u8 channel;
71
72 if (freq == 2484)
73 channel = 14;
74 else
75 channel = (freq - 2407) / 5;
76
77 return channel;
78}
79static inline
80u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm,
81 int freq)
82{
83 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
84 return bcm43xx_freq_to_channel_a(freq);
85 return bcm43xx_freq_to_channel_bg(freq);
86}
87
88/* Lightweight function to convert a channel number to a frequency (in Mhz). */
89static inline
90int bcm43xx_channel_to_freq_a(u8 channel)
91{
92 return (5000 + (5 * channel));
93}
94static inline
95int bcm43xx_channel_to_freq_bg(u8 channel)
96{
97 int freq;
98
99 if (channel == 14)
100 freq = 2484;
101 else
102 freq = 2407 + (5 * channel);
103
104 return freq;
105}
106static inline
107int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
108 u8 channel)
109{
110 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
111 return bcm43xx_channel_to_freq_a(channel);
112 return bcm43xx_channel_to_freq_bg(channel);
113}
114
115/* Lightweight function to check if a channel number is valid.
116 * Note that this does _NOT_ check for geographical restrictions!
117 */
118static inline
119int bcm43xx_is_valid_channel_a(u8 channel)
120{
121 return (channel <= 200);
122}
123static inline
124int bcm43xx_is_valid_channel_bg(u8 channel)
125{
126 return (channel >= 1 && channel <= 14);
127}
128static inline
129int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
130 u8 channel)
131{
132 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
133 return bcm43xx_is_valid_channel_a(channel);
134 return bcm43xx_is_valid_channel_bg(channel);
135}
136
137void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
138void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
139
140void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
141 int iw_mode);
142
143u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm,
144 u16 routing, u16 offset);
145u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm,
146 u16 routing, u16 offset);
147void bcm43xx_shm_write32(struct bcm43xx_private *bcm,
148 u16 routing, u16 offset,
149 u32 value);
150void bcm43xx_shm_write16(struct bcm43xx_private *bcm,
151 u16 routing, u16 offset,
152 u16 value);
153
154void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
155
156int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
157
158void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
159
160void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
161void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
162
163void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
164
165int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
166int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom);
167
168#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..0a66f43ca0c0
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -0,0 +1,2345 @@
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 = bcm43xx_current_phy(bcm);
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 = bcm43xx_current_phy(bcm);
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 mmiowb();
130 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val);
131}
132
133void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
134{
135 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
136 unsigned long flags;
137
138 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
139 if (phy->calibrated)
140 return;
141 if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
142 /* We do not want to be preempted while calibrating
143 * the hardware.
144 */
145 local_irq_save(flags);
146
147 bcm43xx_wireless_core_reset(bcm, 0);
148 bcm43xx_phy_initg(bcm);
149 bcm43xx_wireless_core_reset(bcm, 1);
150
151 local_irq_restore(flags);
152 }
153 phy->calibrated = 1;
154}
155
156/* Connect the PHY
157 * http://bcm-specs.sipsolutions.net/SetPHY
158 */
159int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
160{
161 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
162 u32 flags;
163
164 if (bcm->current_core->rev < 5)
165 goto out;
166
167 flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
168 if (connect) {
169 if (!(flags & 0x00010000))
170 return -ENODEV;
171 flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
172 flags |= (0x800 << 18);
173 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
174 } else {
175 if (!(flags & 0x00020000))
176 return -ENODEV;
177 flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
178 flags &= ~(0x800 << 18);
179 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
180 }
181out:
182 phy->connected = connect;
183 if (connect)
184 dprintk(KERN_INFO PFX "PHY connected\n");
185 else
186 dprintk(KERN_INFO PFX "PHY disconnected\n");
187
188 return 0;
189}
190
191/* intialize B PHY power control
192 * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
193 */
194static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm)
195{
196 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
197 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
198 u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0;
199 int must_reset_txpower = 0;
200
201 assert(phy->type != BCM43xx_PHYTYPE_A);
202 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
203 (bcm->board_type == 0x0416))
204 return;
205
206 bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF);
207 bcm43xx_phy_write(bcm, 0x0028, 0x8018);
208
209 if (phy->type == BCM43xx_PHYTYPE_G) {
210 if (!phy->connected)
211 return;
212 bcm43xx_phy_write(bcm, 0x047A, 0xC111);
213 }
214 if (phy->savedpctlreg != 0xFFFF)
215 return;
216
217 if (phy->type == BCM43xx_PHYTYPE_B &&
218 phy->rev >= 2 &&
219 radio->version == 0x2050) {
220 bcm43xx_radio_write16(bcm, 0x0076,
221 bcm43xx_radio_read16(bcm, 0x0076) | 0x0084);
222 } else {
223 saved_batt = radio->baseband_atten;
224 saved_ratt = radio->radio_atten;
225 saved_txctl1 = radio->txctl1;
226 if ((radio->revision >= 6) && (radio->revision <= 8)
227 && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
228 bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0);
229 else
230 bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0);
231 must_reset_txpower = 1;
232 }
233 bcm43xx_dummy_transmission(bcm);
234
235 phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL);
236
237 if (must_reset_txpower)
238 bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1);
239 else
240 bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B);
241 bcm43xx_radio_clear_tssi(bcm);
242}
243
244static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
245{
246 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
247 u16 offset = 0x0000;
248
249 if (phy->rev == 1)
250 offset = 0x4C00;
251
252 bcm43xx_ilt_write(bcm, offset, 0x00FE);
253 bcm43xx_ilt_write(bcm, offset + 1, 0x000D);
254 bcm43xx_ilt_write(bcm, offset + 2, 0x0013);
255 bcm43xx_ilt_write(bcm, offset + 3, 0x0019);
256
257 if (phy->rev == 1) {
258 bcm43xx_ilt_write(bcm, 0x1800, 0x2710);
259 bcm43xx_ilt_write(bcm, 0x1801, 0x9B83);
260 bcm43xx_ilt_write(bcm, 0x1802, 0x9B83);
261 bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D);
262 bcm43xx_phy_write(bcm, 0x0455, 0x0004);
263 }
264
265 bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700);
266 bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F);
267 bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80);
268 bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300);
269
270 bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008);
271
272 bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008);
273 bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600);
274 bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700);
275 bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100);
276
277 if (phy->rev == 1)
278 bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007);
279
280 bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C);
281 bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200);
282 bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C);
283 bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020);
284 bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200);
285 bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E);
286 bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00);
287 bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028);
288 bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00);
289
290 if (phy->rev == 1) {
291 bcm43xx_phy_write(bcm, 0x0430, 0x092B);
292 bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002);
293 } else {
294 bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1);
295 bcm43xx_phy_write(bcm, 0x041F, 0x287A);
296 bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004);
297 }
298
299 if (phy->rev > 2) {
300 bcm43xx_phy_write(bcm, 0x0422, 0x287A);
301 bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000);
302 }
303
304 bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
305 bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
306
307 if (phy->rev == 1) {
308 bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
309 bcm43xx_phy_write(bcm, 0x048B, 0x005E);
310 bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
311 bcm43xx_phy_write(bcm, 0x048D, 0x0002);
312 }
313
314 bcm43xx_ilt_write(bcm, offset + 0x0800, 0);
315 bcm43xx_ilt_write(bcm, offset + 0x0801, 7);
316 bcm43xx_ilt_write(bcm, offset + 0x0802, 16);
317 bcm43xx_ilt_write(bcm, offset + 0x0803, 28);
318}
319
320static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
321{
322 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
323 u16 i;
324
325 assert(phy->type == BCM43xx_PHYTYPE_G);
326 if (phy->rev == 1) {
327 bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
328 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
329 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
330 bcm43xx_phy_write(bcm, 0x042C, 0x005A);
331 bcm43xx_phy_write(bcm, 0x0427, 0x001A);
332
333 for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++)
334 bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]);
335 for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++)
336 bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]);
337 for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
338 bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
339 } else {
340 /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
341 bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654);
342
343 if (phy->rev == 2) {
344 bcm43xx_phy_write(bcm, 0x04C0, 0x1861);
345 bcm43xx_phy_write(bcm, 0x04C1, 0x0271);
346 } else if (phy->rev > 2) {
347 bcm43xx_phy_write(bcm, 0x04C0, 0x0098);
348 bcm43xx_phy_write(bcm, 0x04C1, 0x0070);
349 bcm43xx_phy_write(bcm, 0x04C9, 0x0080);
350 }
351 bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800);
352
353 for (i = 0; i < 64; i++)
354 bcm43xx_ilt_write(bcm, 0x4000 + i, i);
355 for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++)
356 bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]);
357 }
358
359 if (phy->rev <= 2)
360 for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
361 bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
362 else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
363 for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
364 bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
365 else
366 for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
367 bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]);
368
369 if (phy->rev == 2)
370 for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
371 bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
372 else if ((phy->rev > 2) && (phy->rev <= 7))
373 for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
374 bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
375
376 if (phy->rev == 1) {
377 for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
378 bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
379 for (i = 0; i < 4; i++) {
380 bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020);
381 bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020);
382 bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020);
383 bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020);
384 }
385 bcm43xx_phy_agcsetup(bcm);
386
387 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
388 (bcm->board_type == 0x0416) &&
389 (bcm->board_revision == 0x0017))
390 return;
391
392 bcm43xx_ilt_write(bcm, 0x5001, 0x0002);
393 bcm43xx_ilt_write(bcm, 0x5002, 0x0001);
394 } else {
395 for (i = 0; i <= 0x2F; i++)
396 bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820);
397 bcm43xx_phy_agcsetup(bcm);
398 bcm43xx_phy_read(bcm, 0x0400); /* dummy read */
399 bcm43xx_phy_write(bcm, 0x0403, 0x1000);
400 bcm43xx_ilt_write(bcm, 0x3C02, 0x000F);
401 bcm43xx_ilt_write(bcm, 0x3C03, 0x0014);
402
403 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) &&
404 (bcm->board_type == 0x0416) &&
405 (bcm->board_revision == 0x0017))
406 return;
407
408 bcm43xx_ilt_write(bcm, 0x0401, 0x0002);
409 bcm43xx_ilt_write(bcm, 0x0402, 0x0001);
410 }
411}
412
413/* Initialize the noisescaletable for APHY */
414static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm)
415{
416 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
417 int i;
418
419 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400);
420 for (i = 0; i < 12; i++) {
421 if (phy->rev == 2)
422 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
423 else
424 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
425 }
426 if (phy->rev == 2)
427 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700);
428 else
429 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300);
430 for (i = 0; i < 11; i++) {
431 if (phy->rev == 2)
432 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767);
433 else
434 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323);
435 }
436 if (phy->rev == 2)
437 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067);
438 else
439 bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023);
440}
441
442static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm)
443{
444 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
445 u16 i;
446
447 assert(phy->type == BCM43xx_PHYTYPE_A);
448 switch (phy->rev) {
449 case 2:
450 bcm43xx_phy_write(bcm, 0x008E, 0x3800);
451 bcm43xx_phy_write(bcm, 0x0035, 0x03FF);
452 bcm43xx_phy_write(bcm, 0x0036, 0x0400);
453
454 bcm43xx_ilt_write(bcm, 0x3807, 0x0051);
455
456 bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
457 bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
458 bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF);
459 bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
460
461 bcm43xx_phy_write(bcm, 0x0024, 0x4680);
462 bcm43xx_phy_write(bcm, 0x0020, 0x0003);
463 bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
464 bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
465
466 bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
467 bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF);
468 bcm43xx_phy_write(bcm, 0x008E, 0x58C1);
469
470 bcm43xx_ilt_write(bcm, 0x0803, 0x000F);
471 bcm43xx_ilt_write(bcm, 0x0804, 0x001F);
472 bcm43xx_ilt_write(bcm, 0x0805, 0x002A);
473 bcm43xx_ilt_write(bcm, 0x0805, 0x0030);
474 bcm43xx_ilt_write(bcm, 0x0807, 0x003A);
475
476 bcm43xx_ilt_write(bcm, 0x0000, 0x0013);
477 bcm43xx_ilt_write(bcm, 0x0001, 0x0013);
478 bcm43xx_ilt_write(bcm, 0x0002, 0x0013);
479 bcm43xx_ilt_write(bcm, 0x0003, 0x0013);
480 bcm43xx_ilt_write(bcm, 0x0004, 0x0015);
481 bcm43xx_ilt_write(bcm, 0x0005, 0x0015);
482 bcm43xx_ilt_write(bcm, 0x0006, 0x0019);
483
484 bcm43xx_ilt_write(bcm, 0x0404, 0x0003);
485 bcm43xx_ilt_write(bcm, 0x0405, 0x0003);
486 bcm43xx_ilt_write(bcm, 0x0406, 0x0007);
487
488 for (i = 0; i < 16; i++)
489 bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F);
490
491 bcm43xx_ilt_write(bcm, 0x3003, 0x1044);
492 bcm43xx_ilt_write(bcm, 0x3004, 0x7201);
493 bcm43xx_ilt_write(bcm, 0x3006, 0x0040);
494 bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008);
495
496 for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++)
497 bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]);
498 for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++)
499 bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]);
500 for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
501 bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
502 bcm43xx_phy_init_noisescaletbl(bcm);
503 for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
504 bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
505 break;
506 case 3:
507 for (i = 0; i < 64; i++)
508 bcm43xx_ilt_write(bcm, 0x4000 + i, i);
509
510 bcm43xx_ilt_write(bcm, 0x3807, 0x0051);
511
512 bcm43xx_phy_write(bcm, 0x001C, 0x0FF9);
513 bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F);
514 bcm43xx_radio_write16(bcm, 0x0002, 0x07BF);
515
516 bcm43xx_phy_write(bcm, 0x0024, 0x4680);
517 bcm43xx_phy_write(bcm, 0x0020, 0x0003);
518 bcm43xx_phy_write(bcm, 0x001D, 0x0F40);
519 bcm43xx_phy_write(bcm, 0x001F, 0x1C00);
520 bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400);
521
522 bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008);
523 for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++)
524 bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]);
525 bcm43xx_phy_init_noisescaletbl(bcm);
526 for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
527 bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
528
529 bcm43xx_phy_write(bcm, 0x0003, 0x1808);
530
531 bcm43xx_ilt_write(bcm, 0x0803, 0x000F);
532 bcm43xx_ilt_write(bcm, 0x0804, 0x001F);
533 bcm43xx_ilt_write(bcm, 0x0805, 0x002A);
534 bcm43xx_ilt_write(bcm, 0x0805, 0x0030);
535 bcm43xx_ilt_write(bcm, 0x0807, 0x003A);
536
537 bcm43xx_ilt_write(bcm, 0x0000, 0x0013);
538 bcm43xx_ilt_write(bcm, 0x0001, 0x0013);
539 bcm43xx_ilt_write(bcm, 0x0002, 0x0013);
540 bcm43xx_ilt_write(bcm, 0x0003, 0x0013);
541 bcm43xx_ilt_write(bcm, 0x0004, 0x0015);
542 bcm43xx_ilt_write(bcm, 0x0005, 0x0015);
543 bcm43xx_ilt_write(bcm, 0x0006, 0x0019);
544
545 bcm43xx_ilt_write(bcm, 0x0404, 0x0003);
546 bcm43xx_ilt_write(bcm, 0x0405, 0x0003);
547 bcm43xx_ilt_write(bcm, 0x0406, 0x0007);
548
549 bcm43xx_ilt_write(bcm, 0x3C02, 0x000F);
550 bcm43xx_ilt_write(bcm, 0x3C03, 0x0014);
551 break;
552 default:
553 assert(0);
554 }
555}
556
557/* Initialize APHY. This is also called for the GPHY in some cases. */
558static void bcm43xx_phy_inita(struct bcm43xx_private *bcm)
559{
560 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
561 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
562 u16 tval;
563
564 if (phy->type == BCM43xx_PHYTYPE_A) {
565 bcm43xx_phy_setupa(bcm);
566 } else {
567 bcm43xx_phy_setupg(bcm);
568 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
569 bcm43xx_phy_write(bcm, 0x046E, 0x03CF);
570 return;
571 }
572
573 bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
574 (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340);
575 bcm43xx_phy_write(bcm, 0x0034, 0x0001);
576
577 TODO();//TODO: RSSI AGC
578 bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS,
579 bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14));
580 bcm43xx_radio_init2060(bcm);
581
582 if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)
583 && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) {
584 if (radio->lofcal == 0xFFFF) {
585 TODO();//TODO: LOF Cal
586 bcm43xx_radio_set_tx_iq(bcm);
587 } else
588 bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal);
589 }
590
591 bcm43xx_phy_write(bcm, 0x007A, 0xF111);
592
593 if (phy->savedpctlreg == 0xFFFF) {
594 bcm43xx_radio_write16(bcm, 0x0019, 0x0000);
595 bcm43xx_radio_write16(bcm, 0x0017, 0x0020);
596
597 tval = bcm43xx_ilt_read(bcm, 0x3001);
598 if (phy->rev == 1) {
599 bcm43xx_ilt_write(bcm, 0x3001,
600 (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87)
601 | 0x0058);
602 } else {
603 bcm43xx_ilt_write(bcm, 0x3001,
604 (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3)
605 | 0x002C);
606 }
607 bcm43xx_dummy_transmission(bcm);
608 phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL);
609 bcm43xx_ilt_write(bcm, 0x3001, tval);
610
611 bcm43xx_radio_set_txpower_a(bcm, 0x0018);
612 }
613 bcm43xx_radio_clear_tssi(bcm);
614}
615
616static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm)
617{
618 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
619 u16 offset, val;
620
621 bcm43xx_write16(bcm, 0x03EC, 0x3F22);
622 bcm43xx_phy_write(bcm, 0x0020, 0x301C);
623 bcm43xx_phy_write(bcm, 0x0026, 0x0000);
624 bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
625 bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
626 val = 0x3C3D;
627 for (offset = 0x0089; offset < 0x00A7; offset++) {
628 bcm43xx_phy_write(bcm, offset, val);
629 val -= 0x0202;
630 }
631 bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
632 if (radio->channel == 0xFF)
633 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
634 else
635 bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
636 if (radio->version != 0x2050) {
637 bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
638 bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
639 }
640 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
641 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
642 if (radio->version == 0x2050) {
643 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
644 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
645 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
646 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
647 bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
648 bcm43xx_phy_write(bcm, 0x0038, 0x0677);
649 bcm43xx_radio_init2050(bcm);
650 }
651 bcm43xx_phy_write(bcm, 0x0014, 0x0080);
652 bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
653 bcm43xx_phy_write(bcm, 0x0032, 0x00CC);
654 bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
655 bcm43xx_phy_lo_b_measure(bcm);
656 bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
657 if (radio->version != 0x2050)
658 bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
659 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000);
660 bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
661 if (radio->version != 0x2050)
662 bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
663 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
664 bcm43xx_phy_init_pctl(bcm);
665}
666
667static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm)
668{
669 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
670 u16 offset, val;
671
672 bcm43xx_write16(bcm, 0x03EC, 0x3F22);
673 bcm43xx_phy_write(bcm, 0x0020, 0x301C);
674 bcm43xx_phy_write(bcm, 0x0026, 0x0000);
675 bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
676 bcm43xx_phy_write(bcm, 0x0088, 0x3E00);
677 val = 0x3C3D;
678 for (offset = 0x0089; offset < 0x00A7; offset++) {
679 bcm43xx_phy_write(bcm, offset, val);
680 val -= 0x0202;
681 }
682 bcm43xx_phy_write(bcm, 0x03E4, 0x3000);
683 if (radio->channel == 0xFF)
684 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
685 else
686 bcm43xx_radio_selectchannel(bcm, radio->channel, 0);
687 if (radio->version != 0x2050) {
688 bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
689 bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
690 }
691 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
692 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
693 if (radio->version == 0x2050) {
694 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
695 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
696 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
697 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
698 bcm43xx_radio_write16(bcm, 0x007A, 0x000F);
699 bcm43xx_phy_write(bcm, 0x0038, 0x0677);
700 bcm43xx_radio_init2050(bcm);
701 }
702 bcm43xx_phy_write(bcm, 0x0014, 0x0080);
703 bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
704 if (radio->version == 0x2050)
705 bcm43xx_phy_write(bcm, 0x0032, 0x00E0);
706 bcm43xx_phy_write(bcm, 0x0035, 0x07C2);
707
708 bcm43xx_phy_lo_b_measure(bcm);
709
710 bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
711 if (radio->version == 0x2050)
712 bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
713 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100);
714 bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
715 if (radio->version == 0x2050)
716 bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
717 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
718 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
719 bcm43xx_calc_nrssi_slope(bcm);
720 bcm43xx_calc_nrssi_threshold(bcm);
721 }
722 bcm43xx_phy_init_pctl(bcm);
723}
724
725static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
726{
727 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
728 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
729 u16 offset;
730
731 if (phy->version == 1 &&
732 radio->version == 0x2050) {
733 bcm43xx_radio_write16(bcm, 0x007A,
734 bcm43xx_radio_read16(bcm, 0x007A)
735 | 0x0050);
736 }
737 if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) &&
738 (bcm->board_type != 0x0416)) {
739 for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
740 bcm43xx_phy_write(bcm, offset,
741 (bcm43xx_phy_read(bcm, offset) + 0x2020)
742 & 0x3F3F);
743 }
744 }
745 bcm43xx_phy_write(bcm, 0x0035,
746 (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF)
747 | 0x0700);
748 if (radio->version == 0x2050)
749 bcm43xx_phy_write(bcm, 0x0038, 0x0667);
750
751 if (phy->connected) {
752 if (radio->version == 0x2050) {
753 bcm43xx_radio_write16(bcm, 0x007A,
754 bcm43xx_radio_read16(bcm, 0x007A)
755 | 0x0020);
756 bcm43xx_radio_write16(bcm, 0x0051,
757 bcm43xx_radio_read16(bcm, 0x0051)
758 | 0x0004);
759 }
760 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000);
761
762 bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
763 bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
764
765 bcm43xx_phy_write(bcm, 0x001C, 0x186A);
766
767 bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900);
768 bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064);
769 bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A);
770 }
771
772 if (bcm->bad_frames_preempt) {
773 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
774 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11));
775 }
776
777 if (phy->version == 1 && radio->version == 0x2050) {
778 bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
779 bcm43xx_phy_write(bcm, 0x0021, 0x3763);
780 bcm43xx_phy_write(bcm, 0x0022, 0x1BC3);
781 bcm43xx_phy_write(bcm, 0x0023, 0x06F9);
782 bcm43xx_phy_write(bcm, 0x0024, 0x037E);
783 } else
784 bcm43xx_phy_write(bcm, 0x0026, 0xCC00);
785 bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
786 bcm43xx_write16(bcm, 0x03EC, 0x3F22);
787
788 if (phy->version == 1 && radio->version == 0x2050)
789 bcm43xx_phy_write(bcm, 0x0020, 0x3E1C);
790 else
791 bcm43xx_phy_write(bcm, 0x0020, 0x301C);
792
793 if (phy->version == 0)
794 bcm43xx_write16(bcm, 0x03E4, 0x3000);
795
796 /* Force to channel 7, even if not supported. */
797 bcm43xx_radio_selectchannel(bcm, 7, 0);
798
799 if (radio->version != 0x2050) {
800 bcm43xx_radio_write16(bcm, 0x0075, 0x0080);
801 bcm43xx_radio_write16(bcm, 0x0079, 0x0081);
802 }
803
804 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
805 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
806
807 if (radio->version == 0x2050) {
808 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
809 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
810 }
811
812 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
813 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
814
815 bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007);
816
817 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
818
819 bcm43xx_phy_write(bcm, 0x0014, 0x0080);
820 bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
821 bcm43xx_phy_write(bcm, 0x88A3, 0x002A);
822
823 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
824
825 if (radio->version == 0x2050)
826 bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
827
828 bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004);
829}
830
831static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
832{
833 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
834 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
835 u16 offset, val;
836
837 bcm43xx_phy_write(bcm, 0x003E, 0x817A);
838 bcm43xx_radio_write16(bcm, 0x007A,
839 (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058));
840 if ((radio->manufact == 0x17F) &&
841 (radio->version == 0x2050) &&
842 (radio->revision == 3 ||
843 radio->revision == 4 ||
844 radio->revision == 5)) {
845 bcm43xx_radio_write16(bcm, 0x0051, 0x001F);
846 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
847 bcm43xx_radio_write16(bcm, 0x0053, 0x005B);
848 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
849 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
850 bcm43xx_radio_write16(bcm, 0x005B, 0x0088);
851 bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
852 bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
853 bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
854 }
855 if ((radio->manufact == 0x17F) &&
856 (radio->version == 0x2050) &&
857 (radio->revision == 6)) {
858 bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
859 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
860 bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
861 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
862 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
863 bcm43xx_radio_write16(bcm, 0x005B, 0x008B);
864 bcm43xx_radio_write16(bcm, 0x005C, 0x00B5);
865 bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
866 bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
867 bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
868 bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
869 bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
870 }
871 if ((radio->manufact == 0x17F) &&
872 (radio->version == 0x2050) &&
873 (radio->revision == 7)) {
874 bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
875 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
876 bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
877 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
878 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
879 bcm43xx_radio_write16(bcm, 0x005B, 0x00A8);
880 bcm43xx_radio_write16(bcm, 0x005C, 0x0075);
881 bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
882 bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
883 bcm43xx_radio_write16(bcm, 0x007D, 0x00E8);
884 bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
885 bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
886 bcm43xx_radio_write16(bcm, 0x007B, 0x0000);
887 }
888 if ((radio->manufact == 0x17F) &&
889 (radio->version == 0x2050) &&
890 (radio->revision == 8)) {
891 bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
892 bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
893 bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
894 bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
895 bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
896 bcm43xx_radio_write16(bcm, 0x005B, 0x006B);
897 bcm43xx_radio_write16(bcm, 0x005C, 0x000F);
898 if (bcm->sprom.boardflags & 0x8000) {
899 bcm43xx_radio_write16(bcm, 0x005D, 0x00FA);
900 bcm43xx_radio_write16(bcm, 0x005E, 0x00D8);
901 } else {
902 bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
903 bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
904 }
905 bcm43xx_radio_write16(bcm, 0x0073, 0x0003);
906 bcm43xx_radio_write16(bcm, 0x007D, 0x00A8);
907 bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
908 bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
909 }
910 val = 0x1E1F;
911 for (offset = 0x0088; offset < 0x0098; offset++) {
912 bcm43xx_phy_write(bcm, offset, val);
913 val -= 0x0202;
914 }
915 val = 0x3E3F;
916 for (offset = 0x0098; offset < 0x00A8; offset++) {
917 bcm43xx_phy_write(bcm, offset, val);
918 val -= 0x0202;
919 }
920 val = 0x2120;
921 for (offset = 0x00A8; offset < 0x00C8; offset++) {
922 bcm43xx_phy_write(bcm, offset, (val & 0x3F3F));
923 val += 0x0202;
924 }
925 if (phy->type == BCM43xx_PHYTYPE_G) {
926 bcm43xx_radio_write16(bcm, 0x007A,
927 bcm43xx_radio_read16(bcm, 0x007A) | 0x0020);
928 bcm43xx_radio_write16(bcm, 0x0051,
929 bcm43xx_radio_read16(bcm, 0x0051) | 0x0004);
930 bcm43xx_phy_write(bcm, 0x0802,
931 bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
932 bcm43xx_phy_write(bcm, 0x042B,
933 bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
934 }
935
936 /* Force to channel 7, even if not supported. */
937 bcm43xx_radio_selectchannel(bcm, 7, 0);
938
939 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
940 bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
941 udelay(40);
942 bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002));
943 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
944 if (radio->manufact == 0x17F &&
945 radio->version == 0x2050 &&
946 radio->revision <= 2) {
947 bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
948 bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
949 bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
950 bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
951 }
952 bcm43xx_radio_write16(bcm, 0x007A,
953 (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007);
954
955 bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
956
957 bcm43xx_phy_write(bcm, 0x0014, 0x0200);
958 if (radio->version == 0x2050){
959 if (radio->revision == 3 ||
960 radio->revision == 4 ||
961 radio->revision == 5)
962 bcm43xx_phy_write(bcm, 0x002A, 0x8AC0);
963 else
964 bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
965 }
966 bcm43xx_phy_write(bcm, 0x0038, 0x0668);
967 bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
968 if (radio->version == 0x2050) {
969 if (radio->revision == 3 ||
970 radio->revision == 4 ||
971 radio->revision == 5)
972 bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003);
973 else if (radio->revision <= 2)
974 bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
975 }
976
977 if (phy->rev == 4)
978 bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004);
979 else
980 bcm43xx_write16(bcm, 0x03E4, 0x0009);
981 if (phy->type == BCM43xx_PHYTYPE_B) {
982 bcm43xx_write16(bcm, 0x03E6, 0x8140);
983 bcm43xx_phy_write(bcm, 0x0016, 0x0410);
984 bcm43xx_phy_write(bcm, 0x0017, 0x0820);
985 bcm43xx_phy_write(bcm, 0x0062, 0x0007);
986 (void) bcm43xx_radio_calibrationvalue(bcm);
987 bcm43xx_phy_lo_b_measure(bcm);
988 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
989 bcm43xx_calc_nrssi_slope(bcm);
990 bcm43xx_calc_nrssi_threshold(bcm);
991 }
992 bcm43xx_phy_init_pctl(bcm);
993 } else
994 bcm43xx_write16(bcm, 0x03E6, 0x0);
995}
996
997static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm)
998{
999 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1000 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1001 u16 backup_phy[15];
1002 u16 backup_radio[3];
1003 u16 backup_bband;
1004 u16 i;
1005 u16 loop1_cnt, loop1_done, loop1_omitted;
1006 u16 loop2_done;
1007
1008 backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429);
1009 backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001);
1010 backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811);
1011 backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812);
1012 backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814);
1013 backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815);
1014 backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A);
1015 backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059);
1016 backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058);
1017 backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A);
1018 backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003);
1019 backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F);
1020 backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810);
1021 backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B);
1022 backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015);
1023 bcm43xx_phy_read(bcm, 0x002D); /* dummy read */
1024 backup_bband = radio->baseband_atten;
1025 backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052);
1026 backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043);
1027 backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A);
1028
1029 bcm43xx_phy_write(bcm, 0x0429,
1030 bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF);
1031 bcm43xx_phy_write(bcm, 0x0001,
1032 bcm43xx_phy_read(bcm, 0x0001) & 0x8000);
1033 bcm43xx_phy_write(bcm, 0x0811,
1034 bcm43xx_phy_read(bcm, 0x0811) | 0x0002);
1035 bcm43xx_phy_write(bcm, 0x0812,
1036 bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD);
1037 bcm43xx_phy_write(bcm, 0x0811,
1038 bcm43xx_phy_read(bcm, 0x0811) | 0x0001);
1039 bcm43xx_phy_write(bcm, 0x0812,
1040 bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE);
1041 bcm43xx_phy_write(bcm, 0x0814,
1042 bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
1043 bcm43xx_phy_write(bcm, 0x0815,
1044 bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
1045 bcm43xx_phy_write(bcm, 0x0814,
1046 bcm43xx_phy_read(bcm, 0x0814) | 0x0002);
1047 bcm43xx_phy_write(bcm, 0x0815,
1048 bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD);
1049 bcm43xx_phy_write(bcm, 0x0811,
1050 bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
1051 bcm43xx_phy_write(bcm, 0x0812,
1052 bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
1053
1054 bcm43xx_phy_write(bcm, 0x0811,
1055 (bcm43xx_phy_read(bcm, 0x0811)
1056 & 0xFFCF) | 0x0030);
1057 bcm43xx_phy_write(bcm, 0x0812,
1058 (bcm43xx_phy_read(bcm, 0x0812)
1059 & 0xFFCF) | 0x0010);
1060
1061 bcm43xx_phy_write(bcm, 0x005A, 0x0780);
1062 bcm43xx_phy_write(bcm, 0x0059, 0xC810);
1063 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
1064 if (phy->version == 0) {
1065 bcm43xx_phy_write(bcm, 0x0003, 0x0122);
1066 } else {
1067 bcm43xx_phy_write(bcm, 0x000A,
1068 bcm43xx_phy_read(bcm, 0x000A)
1069 | 0x2000);
1070 }
1071 bcm43xx_phy_write(bcm, 0x0814,
1072 bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
1073 bcm43xx_phy_write(bcm, 0x0815,
1074 bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
1075 bcm43xx_phy_write(bcm, 0x0003,
1076 (bcm43xx_phy_read(bcm, 0x0003)
1077 & 0xFF9F) | 0x0040);
1078 if (radio->version == 0x2050 && radio->revision == 2) {
1079 bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
1080 bcm43xx_radio_write16(bcm, 0x0043,
1081 (bcm43xx_radio_read16(bcm, 0x0043)
1082 & 0xFFF0) | 0x0009);
1083 loop1_cnt = 9;
1084 } else if (radio->revision == 8) {
1085 bcm43xx_radio_write16(bcm, 0x0043, 0x000F);
1086 loop1_cnt = 15;
1087 } else
1088 loop1_cnt = 0;
1089
1090 bcm43xx_phy_set_baseband_attenuation(bcm, 11);
1091
1092 if (phy->rev >= 3)
1093 bcm43xx_phy_write(bcm, 0x080F, 0xC020);
1094 else
1095 bcm43xx_phy_write(bcm, 0x080F, 0x8020);
1096 bcm43xx_phy_write(bcm, 0x0810, 0x0000);
1097
1098 bcm43xx_phy_write(bcm, 0x002B,
1099 (bcm43xx_phy_read(bcm, 0x002B)
1100 & 0xFFC0) | 0x0001);
1101 bcm43xx_phy_write(bcm, 0x002B,
1102 (bcm43xx_phy_read(bcm, 0x002B)
1103 & 0xC0FF) | 0x0800);
1104 bcm43xx_phy_write(bcm, 0x0811,
1105 bcm43xx_phy_read(bcm, 0x0811) | 0x0100);
1106 bcm43xx_phy_write(bcm, 0x0812,
1107 bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF);
1108 if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) {
1109 if (phy->rev >= 7) {
1110 bcm43xx_phy_write(bcm, 0x0811,
1111 bcm43xx_phy_read(bcm, 0x0811)
1112 | 0x0800);
1113 bcm43xx_phy_write(bcm, 0x0812,
1114 bcm43xx_phy_read(bcm, 0x0812)
1115 | 0x8000);
1116 }
1117 }
1118 bcm43xx_radio_write16(bcm, 0x007A,
1119 bcm43xx_radio_read16(bcm, 0x007A)
1120 & 0x00F7);
1121
1122 for (i = 0; i < loop1_cnt; i++) {
1123 bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt);
1124 bcm43xx_phy_write(bcm, 0x0812,
1125 (bcm43xx_phy_read(bcm, 0x0812)
1126 & 0xF0FF) | (i << 8));
1127 bcm43xx_phy_write(bcm, 0x0015,
1128 (bcm43xx_phy_read(bcm, 0x0015)
1129 & 0x0FFF) | 0xA000);
1130 bcm43xx_phy_write(bcm, 0x0015,
1131 (bcm43xx_phy_read(bcm, 0x0015)
1132 & 0x0FFF) | 0xF000);
1133 udelay(20);
1134 if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC)
1135 break;
1136 }
1137 loop1_done = i;
1138 loop1_omitted = loop1_cnt - loop1_done;
1139
1140 loop2_done = 0;
1141 if (loop1_done >= 8) {
1142 bcm43xx_phy_write(bcm, 0x0812,
1143 bcm43xx_phy_read(bcm, 0x0812)
1144 | 0x0030);
1145 for (i = loop1_done - 8; i < 16; i++) {
1146 bcm43xx_phy_write(bcm, 0x0812,
1147 (bcm43xx_phy_read(bcm, 0x0812)
1148 & 0xF0FF) | (i << 8));
1149 bcm43xx_phy_write(bcm, 0x0015,
1150 (bcm43xx_phy_read(bcm, 0x0015)
1151 & 0x0FFF) | 0xA000);
1152 bcm43xx_phy_write(bcm, 0x0015,
1153 (bcm43xx_phy_read(bcm, 0x0015)
1154 & 0x0FFF) | 0xF000);
1155 udelay(20);
1156 if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC)
1157 break;
1158 }
1159 }
1160
1161 bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]);
1162 bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]);
1163 bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]);
1164 bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]);
1165 bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]);
1166 bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]);
1167 bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]);
1168 bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]);
1169 bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]);
1170 bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]);
1171 bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]);
1172
1173 bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband);
1174
1175 bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]);
1176 bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]);
1177 bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]);
1178
1179 bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003);
1180 udelay(10);
1181 bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]);
1182 bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]);
1183 bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]);
1184 bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]);
1185
1186 phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
1187 phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
1188}
1189
1190static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
1191{
1192 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1193 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1194 u16 tmp;
1195
1196 if (phy->rev == 1)
1197 bcm43xx_phy_initb5(bcm);
1198 else if (phy->rev >= 2 && phy->rev <= 7)
1199 bcm43xx_phy_initb6(bcm);
1200 if (phy->rev >= 2 || phy->connected)
1201 bcm43xx_phy_inita(bcm);
1202
1203 if (phy->rev >= 2) {
1204 bcm43xx_phy_write(bcm, 0x0814, 0x0000);
1205 bcm43xx_phy_write(bcm, 0x0815, 0x0000);
1206 if (phy->rev == 2)
1207 bcm43xx_phy_write(bcm, 0x0811, 0x0000);
1208 else if (phy->rev >= 3)
1209 bcm43xx_phy_write(bcm, 0x0811, 0x0400);
1210 bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
1211 if (phy->connected) {
1212 tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF;
1213 if (tmp < 6) {
1214 bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
1215 bcm43xx_phy_write(bcm, 0x04C3, 0x8006);
1216 if (tmp != 3) {
1217 bcm43xx_phy_write(bcm, 0x04CC,
1218 (bcm43xx_phy_read(bcm, 0x04CC)
1219 & 0x00FF) | 0x1F00);
1220 }
1221 }
1222 }
1223 }
1224 if (phy->rev < 3 && phy->connected)
1225 bcm43xx_phy_write(bcm, 0x047E, 0x0078);
1226 if (phy->rev >= 6 && phy->rev <= 8) {
1227 bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080);
1228 bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004);
1229 }
1230 if (phy->rev >= 2 && phy->connected)
1231 bcm43xx_calc_loopback_gain(bcm);
1232 if (radio->revision != 8) {
1233 if (radio->initval == 0xFFFF)
1234 radio->initval = bcm43xx_radio_init2050(bcm);
1235 else
1236 bcm43xx_radio_write16(bcm, 0x0078, radio->initval);
1237 }
1238 if (radio->txctl2 == 0xFFFF) {
1239 bcm43xx_phy_lo_g_measure(bcm);
1240 } else {
1241 if (radio->version == 0x2050 && radio->revision == 8) {
1242 //FIXME
1243 } else {
1244 bcm43xx_radio_write16(bcm, 0x0052,
1245 (bcm43xx_radio_read16(bcm, 0x0052)
1246 & 0xFFF0) | radio->txctl1);
1247 }
1248 if (phy->rev >= 6) {
1249 /*
1250 bcm43xx_phy_write(bcm, 0x0036,
1251 (bcm43xx_phy_read(bcm, 0x0036)
1252 & 0xF000) | (FIXME << 12));
1253 */
1254 }
1255 if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
1256 bcm43xx_phy_write(bcm, 0x002E, 0x8075);
1257 else
1258 bcm43xx_phy_write(bcm, 0x003E, 0x807F);
1259 if (phy->rev < 2)
1260 bcm43xx_phy_write(bcm, 0x002F, 0x0101);
1261 else
1262 bcm43xx_phy_write(bcm, 0x002F, 0x0202);
1263 }
1264 if (phy->connected) {
1265 bcm43xx_phy_lo_adjust(bcm, 0);
1266 bcm43xx_phy_write(bcm, 0x080F, 0x8078);
1267 }
1268
1269 if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
1270 /* The specs state to update the NRSSI LT with
1271 * the value 0x7FFFFFFF here. I think that is some weird
1272 * compiler optimization in the original driver.
1273 * Essentially, what we do here is resetting all NRSSI LT
1274 * entries to -32 (see the limit_value() in nrssi_hw_update())
1275 */
1276 bcm43xx_nrssi_hw_update(bcm, 0xFFFF);
1277 bcm43xx_calc_nrssi_threshold(bcm);
1278 } else if (phy->connected) {
1279 if (radio->nrssi[0] == -1000) {
1280 assert(radio->nrssi[1] == -1000);
1281 bcm43xx_calc_nrssi_slope(bcm);
1282 } else {
1283 assert(radio->nrssi[1] != -1000);
1284 bcm43xx_calc_nrssi_threshold(bcm);
1285 }
1286 }
1287 if (radio->revision == 8)
1288 bcm43xx_phy_write(bcm, 0x0805, 0x3230);
1289 bcm43xx_phy_init_pctl(bcm);
1290 if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) {
1291 bcm43xx_phy_write(bcm, 0x0429,
1292 bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF);
1293 bcm43xx_phy_write(bcm, 0x04C3,
1294 bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF);
1295 }
1296}
1297
1298static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
1299{
1300 int i;
1301 u16 ret = 0;
1302
1303 for (i = 0; i < 10; i++){
1304 bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
1305 udelay(1);
1306 bcm43xx_phy_write(bcm, 0x0015, 0xEFA0);
1307 udelay(10);
1308 bcm43xx_phy_write(bcm, 0x0015, 0xFFA0);
1309 udelay(40);
1310 ret += bcm43xx_phy_read(bcm, 0x002C);
1311 }
1312
1313 return ret;
1314}
1315
1316void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm)
1317{
1318 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1319 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1320 u16 regstack[12] = { 0 };
1321 u16 mls;
1322 u16 fval;
1323 int i, j;
1324
1325 regstack[0] = bcm43xx_phy_read(bcm, 0x0015);
1326 regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0;
1327
1328 if (radio->version == 0x2053) {
1329 regstack[2] = bcm43xx_phy_read(bcm, 0x000A);
1330 regstack[3] = bcm43xx_phy_read(bcm, 0x002A);
1331 regstack[4] = bcm43xx_phy_read(bcm, 0x0035);
1332 regstack[5] = bcm43xx_phy_read(bcm, 0x0003);
1333 regstack[6] = bcm43xx_phy_read(bcm, 0x0001);
1334 regstack[7] = bcm43xx_phy_read(bcm, 0x0030);
1335
1336 regstack[8] = bcm43xx_radio_read16(bcm, 0x0043);
1337 regstack[9] = bcm43xx_radio_read16(bcm, 0x007A);
1338 regstack[10] = bcm43xx_read16(bcm, 0x03EC);
1339 regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0;
1340
1341 bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
1342 bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
1343 bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F);
1344 bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0);
1345 }
1346 bcm43xx_phy_write(bcm, 0x0015, 0xB000);
1347 bcm43xx_phy_write(bcm, 0x002B, 0x0004);
1348
1349 if (radio->version == 0x2053) {
1350 bcm43xx_phy_write(bcm, 0x002B, 0x0203);
1351 bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
1352 }
1353
1354 phy->minlowsig[0] = 0xFFFF;
1355
1356 for (i = 0; i < 4; i++) {
1357 bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
1358 bcm43xx_phy_lo_b_r15_loop(bcm);
1359 }
1360 for (i = 0; i < 10; i++) {
1361 bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i);
1362 mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
1363 if (mls < phy->minlowsig[0]) {
1364 phy->minlowsig[0] = mls;
1365 phy->minlowsigpos[0] = i;
1366 }
1367 }
1368 bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]);
1369
1370 phy->minlowsig[1] = 0xFFFF;
1371
1372 for (i = -4; i < 5; i += 2) {
1373 for (j = -4; j < 5; j += 2) {
1374 if (j < 0)
1375 fval = (0x0100 * i) + j + 0x0100;
1376 else
1377 fval = (0x0100 * i) + j;
1378 bcm43xx_phy_write(bcm, 0x002F, fval);
1379 mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10;
1380 if (mls < phy->minlowsig[1]) {
1381 phy->minlowsig[1] = mls;
1382 phy->minlowsigpos[1] = fval;
1383 }
1384 }
1385 }
1386 phy->minlowsigpos[1] += 0x0101;
1387
1388 bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]);
1389 if (radio->version == 0x2053) {
1390 bcm43xx_phy_write(bcm, 0x000A, regstack[2]);
1391 bcm43xx_phy_write(bcm, 0x002A, regstack[3]);
1392 bcm43xx_phy_write(bcm, 0x0035, regstack[4]);
1393 bcm43xx_phy_write(bcm, 0x0003, regstack[5]);
1394 bcm43xx_phy_write(bcm, 0x0001, regstack[6]);
1395 bcm43xx_phy_write(bcm, 0x0030, regstack[7]);
1396
1397 bcm43xx_radio_write16(bcm, 0x0043, regstack[8]);
1398 bcm43xx_radio_write16(bcm, 0x007A, regstack[9]);
1399
1400 bcm43xx_radio_write16(bcm, 0x0052,
1401 (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F)
1402 | regstack[11]);
1403
1404 bcm43xx_write16(bcm, 0x03EC, regstack[10]);
1405 }
1406 bcm43xx_phy_write(bcm, 0x0015, regstack[0]);
1407}
1408
1409static inline
1410u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
1411{
1412 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1413
1414 if (phy->connected) {
1415 bcm43xx_phy_write(bcm, 0x15, 0xE300);
1416 control <<= 8;
1417 bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0);
1418 udelay(5);
1419 bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2);
1420 udelay(2);
1421 bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3);
1422 udelay(4);
1423 bcm43xx_phy_write(bcm, 0x0015, 0xF300);
1424 udelay(8);
1425 } else {
1426 bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0);
1427 udelay(2);
1428 bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0);
1429 udelay(4);
1430 bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
1431 udelay(8);
1432 }
1433
1434 return bcm43xx_phy_read(bcm, 0x002D);
1435}
1436
1437static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
1438{
1439 int i;
1440 u32 ret = 0;
1441
1442 for (i = 0; i < 8; i++)
1443 ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control);
1444
1445 return ret;
1446}
1447
1448/* Write the LocalOscillator CONTROL */
1449static inline
1450void bcm43xx_lo_write(struct bcm43xx_private *bcm,
1451 struct bcm43xx_lopair *pair)
1452{
1453 u16 value;
1454
1455 value = (u8)(pair->low);
1456 value |= ((u8)(pair->high)) << 8;
1457
1458#ifdef CONFIG_BCM43XX_DEBUG
1459 /* Sanity check. */
1460 if (pair->low < -8 || pair->low > 8 ||
1461 pair->high < -8 || pair->high > 8) {
1462 printk(KERN_WARNING PFX
1463 "WARNING: Writing invalid LOpair "
1464 "(low: %d, high: %d, index: %lu)\n",
1465 pair->low, pair->high,
1466 (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs));
1467 dump_stack();
1468 }
1469#endif
1470
1471 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value);
1472}
1473
1474static inline
1475struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm,
1476 u16 baseband_attenuation,
1477 u16 radio_attenuation,
1478 u16 tx)
1479{
1480 static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
1481 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1482
1483 if (baseband_attenuation > 6)
1484 baseband_attenuation = 6;
1485 assert(radio_attenuation < 10);
1486
1487 if (tx == 3) {
1488 return bcm43xx_get_lopair(phy,
1489 radio_attenuation,
1490 baseband_attenuation);
1491 }
1492 return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation);
1493}
1494
1495static inline
1496struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm)
1497{
1498 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1499
1500 return bcm43xx_find_lopair(bcm,
1501 radio->baseband_atten,
1502 radio->radio_atten,
1503 radio->txctl1);
1504}
1505
1506/* Adjust B/G LO */
1507void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed)
1508{
1509 struct bcm43xx_lopair *pair;
1510
1511 if (fixed) {
1512 /* Use fixed values. Only for initialization. */
1513 pair = bcm43xx_find_lopair(bcm, 2, 3, 0);
1514 } else
1515 pair = bcm43xx_current_lopair(bcm);
1516 bcm43xx_lo_write(bcm, pair);
1517}
1518
1519static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm)
1520{
1521 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1522 u16 txctl2 = 0, i;
1523 u32 smallest, tmp;
1524
1525 bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
1526 udelay(10);
1527 smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
1528 for (i = 0; i < 16; i++) {
1529 bcm43xx_radio_write16(bcm, 0x0052, i);
1530 udelay(10);
1531 tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0);
1532 if (tmp < smallest) {
1533 smallest = tmp;
1534 txctl2 = i;
1535 }
1536 }
1537 radio->txctl2 = txctl2;
1538}
1539
1540static
1541void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm,
1542 const struct bcm43xx_lopair *in_pair,
1543 struct bcm43xx_lopair *out_pair,
1544 u16 r27)
1545{
1546 static const struct bcm43xx_lopair transitions[8] = {
1547 { .high = 1, .low = 1, },
1548 { .high = 1, .low = 0, },
1549 { .high = 1, .low = -1, },
1550 { .high = 0, .low = -1, },
1551 { .high = -1, .low = -1, },
1552 { .high = -1, .low = 0, },
1553 { .high = -1, .low = 1, },
1554 { .high = 0, .low = 1, },
1555 };
1556 struct bcm43xx_lopair lowest_transition = {
1557 .high = in_pair->high,
1558 .low = in_pair->low,
1559 };
1560 struct bcm43xx_lopair tmp_pair;
1561 struct bcm43xx_lopair transition;
1562 int i = 12;
1563 int state = 0;
1564 int found_lower;
1565 int j, begin, end;
1566 u32 lowest_deviation;
1567 u32 tmp;
1568
1569 /* Note that in_pair and out_pair can point to the same pair. Be careful. */
1570
1571 bcm43xx_lo_write(bcm, &lowest_transition);
1572 lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
1573 do {
1574 found_lower = 0;
1575 assert(state >= 0 && state <= 8);
1576 if (state == 0) {
1577 begin = 1;
1578 end = 8;
1579 } else if (state % 2 == 0) {
1580 begin = state - 1;
1581 end = state + 1;
1582 } else {
1583 begin = state - 2;
1584 end = state + 2;
1585 }
1586 if (begin < 1)
1587 begin += 8;
1588 if (end > 8)
1589 end -= 8;
1590
1591 j = begin;
1592 tmp_pair.high = lowest_transition.high;
1593 tmp_pair.low = lowest_transition.low;
1594 while (1) {
1595 assert(j >= 1 && j <= 8);
1596 transition.high = tmp_pair.high + transitions[j - 1].high;
1597 transition.low = tmp_pair.low + transitions[j - 1].low;
1598 if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) {
1599 bcm43xx_lo_write(bcm, &transition);
1600 tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27);
1601 if (tmp < lowest_deviation) {
1602 lowest_deviation = tmp;
1603 state = j;
1604 found_lower = 1;
1605
1606 lowest_transition.high = transition.high;
1607 lowest_transition.low = transition.low;
1608 }
1609 }
1610 if (j == end)
1611 break;
1612 if (j == 8)
1613 j = 1;
1614 else
1615 j++;
1616 }
1617 } while (i-- && found_lower);
1618
1619 out_pair->high = lowest_transition.high;
1620 out_pair->low = lowest_transition.low;
1621}
1622
1623/* Set the baseband attenuation value on chip. */
1624void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
1625 u16 baseband_attenuation)
1626{
1627 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1628 u16 value;
1629
1630 if (phy->version == 0) {
1631 value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0);
1632 value |= (baseband_attenuation & 0x000F);
1633 bcm43xx_write16(bcm, 0x03E6, value);
1634 return;
1635 }
1636
1637 if (phy->version > 1) {
1638 value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
1639 value |= (baseband_attenuation << 2) & 0x003C;
1640 } else {
1641 value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078;
1642 value |= (baseband_attenuation << 3) & 0x0078;
1643 }
1644 bcm43xx_phy_write(bcm, 0x0060, value);
1645}
1646
1647/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
1648void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
1649{
1650 static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
1651 const int is_initializing = bcm43xx_is_initializing(bcm);
1652 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1653 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1654 u16 h, i, oldi = 0, j;
1655 struct bcm43xx_lopair control;
1656 struct bcm43xx_lopair *tmp_control;
1657 u16 tmp;
1658 u16 regstack[16] = { 0 };
1659 u8 oldchannel;
1660
1661 //XXX: What are these?
1662 u8 r27 = 0, r31;
1663
1664 oldchannel = radio->channel;
1665 /* Setup */
1666 if (phy->connected) {
1667 regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
1668 regstack[1] = bcm43xx_phy_read(bcm, 0x0802);
1669 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
1670 bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
1671 }
1672 regstack[3] = bcm43xx_read16(bcm, 0x03E2);
1673 bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000);
1674 regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
1675 regstack[5] = bcm43xx_phy_read(bcm, 0x15);
1676 regstack[6] = bcm43xx_phy_read(bcm, 0x2A);
1677 regstack[7] = bcm43xx_phy_read(bcm, 0x35);
1678 regstack[8] = bcm43xx_phy_read(bcm, 0x60);
1679 regstack[9] = bcm43xx_radio_read16(bcm, 0x43);
1680 regstack[10] = bcm43xx_radio_read16(bcm, 0x7A);
1681 regstack[11] = bcm43xx_radio_read16(bcm, 0x52);
1682 if (phy->connected) {
1683 regstack[12] = bcm43xx_phy_read(bcm, 0x0811);
1684 regstack[13] = bcm43xx_phy_read(bcm, 0x0812);
1685 regstack[14] = bcm43xx_phy_read(bcm, 0x0814);
1686 regstack[15] = bcm43xx_phy_read(bcm, 0x0815);
1687 }
1688 bcm43xx_radio_selectchannel(bcm, 6, 0);
1689 if (phy->connected) {
1690 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF);
1691 bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC);
1692 bcm43xx_dummy_transmission(bcm);
1693 }
1694 bcm43xx_radio_write16(bcm, 0x0043, 0x0006);
1695
1696 bcm43xx_phy_set_baseband_attenuation(bcm, 2);
1697
1698 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000);
1699 bcm43xx_phy_write(bcm, 0x002E, 0x007F);
1700 bcm43xx_phy_write(bcm, 0x080F, 0x0078);
1701 bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7));
1702 bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0);
1703 bcm43xx_phy_write(bcm, 0x002B, 0x0203);
1704 bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
1705 if (phy->connected) {
1706 bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003);
1707 bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC);
1708 bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
1709 bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
1710 }
1711 if (is_initializing)
1712 bcm43xx_phy_lo_g_measure_txctl2(bcm);
1713 bcm43xx_phy_write(bcm, 0x080F, 0x8078);
1714
1715 /* Measure */
1716 control.low = 0;
1717 control.high = 0;
1718 for (h = 0; h < 10; h++) {
1719 /* Loop over each possible RadioAttenuation (0-9) */
1720 i = pairorder[h];
1721 if (is_initializing) {
1722 if (i == 3) {
1723 control.low = 0;
1724 control.high = 0;
1725 } else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
1726 ((i % 2 == 0) && (oldi % 2 == 0))) {
1727 tmp_control = bcm43xx_get_lopair(phy, oldi, 0);
1728 memcpy(&control, tmp_control, sizeof(control));
1729 } else {
1730 tmp_control = bcm43xx_get_lopair(phy, 3, 0);
1731 memcpy(&control, tmp_control, sizeof(control));
1732 }
1733 }
1734 /* Loop over each possible BasebandAttenuation/2 */
1735 for (j = 0; j < 4; j++) {
1736 if (is_initializing) {
1737 tmp = i * 2 + j;
1738 r27 = 0;
1739 r31 = 0;
1740 if (tmp > 14) {
1741 r31 = 1;
1742 if (tmp > 17)
1743 r27 = 1;
1744 if (tmp > 19)
1745 r27 = 2;
1746 }
1747 } else {
1748 tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
1749 if (!tmp_control->used)
1750 continue;
1751 memcpy(&control, tmp_control, sizeof(control));
1752 r27 = 3;
1753 r31 = 0;
1754 }
1755 bcm43xx_radio_write16(bcm, 0x43, i);
1756 bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
1757 udelay(10);
1758
1759 bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
1760
1761 tmp = (regstack[10] & 0xFFF0);
1762 if (r31)
1763 tmp |= 0x0008;
1764 bcm43xx_radio_write16(bcm, 0x007A, tmp);
1765
1766 tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
1767 bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
1768 }
1769 oldi = i;
1770 }
1771 /* Loop over each possible RadioAttenuation (10-13) */
1772 for (i = 10; i < 14; i++) {
1773 /* Loop over each possible BasebandAttenuation/2 */
1774 for (j = 0; j < 4; j++) {
1775 if (is_initializing) {
1776 tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
1777 memcpy(&control, tmp_control, sizeof(control));
1778 tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger.
1779 r27 = 0;
1780 r31 = 0;
1781 if (tmp > 14) {
1782 r31 = 1;
1783 if (tmp > 17)
1784 r27 = 1;
1785 if (tmp > 19)
1786 r27 = 2;
1787 }
1788 } else {
1789 tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2);
1790 if (!tmp_control->used)
1791 continue;
1792 memcpy(&control, tmp_control, sizeof(control));
1793 r27 = 3;
1794 r31 = 0;
1795 }
1796 bcm43xx_radio_write16(bcm, 0x43, i - 9);
1797 bcm43xx_radio_write16(bcm, 0x52,
1798 radio->txctl2
1799 | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
1800 udelay(10);
1801
1802 bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
1803
1804 tmp = (regstack[10] & 0xFFF0);
1805 if (r31)
1806 tmp |= 0x0008;
1807 bcm43xx_radio_write16(bcm, 0x7A, tmp);
1808
1809 tmp_control = bcm43xx_get_lopair(phy, i, j * 2);
1810 bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27);
1811 }
1812 }
1813
1814 /* Restoration */
1815 if (phy->connected) {
1816 bcm43xx_phy_write(bcm, 0x0015, 0xE300);
1817 bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0);
1818 udelay(5);
1819 bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
1820 udelay(2);
1821 bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
1822 } else
1823 bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
1824 bcm43xx_phy_lo_adjust(bcm, is_initializing);
1825 bcm43xx_phy_write(bcm, 0x002E, 0x807F);
1826 if (phy->connected)
1827 bcm43xx_phy_write(bcm, 0x002F, 0x0202);
1828 else
1829 bcm43xx_phy_write(bcm, 0x002F, 0x0101);
1830 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]);
1831 bcm43xx_phy_write(bcm, 0x0015, regstack[5]);
1832 bcm43xx_phy_write(bcm, 0x002A, regstack[6]);
1833 bcm43xx_phy_write(bcm, 0x0035, regstack[7]);
1834 bcm43xx_phy_write(bcm, 0x0060, regstack[8]);
1835 bcm43xx_radio_write16(bcm, 0x0043, regstack[9]);
1836 bcm43xx_radio_write16(bcm, 0x007A, regstack[10]);
1837 regstack[11] &= 0x00F0;
1838 regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F);
1839 bcm43xx_radio_write16(bcm, 0x52, regstack[11]);
1840 bcm43xx_write16(bcm, 0x03E2, regstack[3]);
1841 if (phy->connected) {
1842 bcm43xx_phy_write(bcm, 0x0811, regstack[12]);
1843 bcm43xx_phy_write(bcm, 0x0812, regstack[13]);
1844 bcm43xx_phy_write(bcm, 0x0814, regstack[14]);
1845 bcm43xx_phy_write(bcm, 0x0815, regstack[15]);
1846 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]);
1847 bcm43xx_phy_write(bcm, 0x0802, regstack[1]);
1848 }
1849 bcm43xx_radio_selectchannel(bcm, oldchannel, 1);
1850
1851#ifdef CONFIG_BCM43XX_DEBUG
1852 {
1853 /* Sanity check for all lopairs. */
1854 for (i = 0; i < BCM43xx_LO_COUNT; i++) {
1855 tmp_control = phy->_lo_pairs + i;
1856 if (tmp_control->low < -8 || tmp_control->low > 8 ||
1857 tmp_control->high < -8 || tmp_control->high > 8) {
1858 printk(KERN_WARNING PFX
1859 "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n",
1860 tmp_control->low, tmp_control->high, i);
1861 }
1862 }
1863 }
1864#endif /* CONFIG_BCM43XX_DEBUG */
1865}
1866
1867static
1868void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm)
1869{
1870 struct bcm43xx_lopair *pair;
1871
1872 pair = bcm43xx_current_lopair(bcm);
1873 pair->used = 1;
1874}
1875
1876void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm)
1877{
1878 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1879 struct bcm43xx_lopair *pair;
1880 int i;
1881
1882 for (i = 0; i < BCM43xx_LO_COUNT; i++) {
1883 pair = phy->_lo_pairs + i;
1884 pair->used = 0;
1885 }
1886}
1887
1888/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
1889 * This function converts a TSSI value to dBm in Q5.2
1890 */
1891static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi)
1892{
1893 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1894 s8 dbm = 0;
1895 s32 tmp;
1896
1897 tmp = phy->idle_tssi;
1898 tmp += tssi;
1899 tmp -= phy->savedpctlreg;
1900
1901 switch (phy->type) {
1902 case BCM43xx_PHYTYPE_A:
1903 tmp += 0x80;
1904 tmp = limit_value(tmp, 0x00, 0xFF);
1905 dbm = phy->tssi2dbm[tmp];
1906 TODO(); //TODO: There's a FIXME on the specs
1907 break;
1908 case BCM43xx_PHYTYPE_B:
1909 case BCM43xx_PHYTYPE_G:
1910 tmp = limit_value(tmp, 0x00, 0x3F);
1911 dbm = phy->tssi2dbm[tmp];
1912 break;
1913 default:
1914 assert(0);
1915 }
1916
1917 return dbm;
1918}
1919
1920/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
1921void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm)
1922{
1923 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1924 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1925
1926 if (phy->savedpctlreg == 0xFFFF)
1927 return;
1928 if ((bcm->board_type == 0x0416) &&
1929 (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM))
1930 return;
1931
1932 switch (phy->type) {
1933 case BCM43xx_PHYTYPE_A: {
1934
1935 TODO(); //TODO: Nothing for A PHYs yet :-/
1936
1937 break;
1938 }
1939 case BCM43xx_PHYTYPE_B:
1940 case BCM43xx_PHYTYPE_G: {
1941 u16 tmp;
1942 u16 txpower;
1943 s8 v0, v1, v2, v3;
1944 s8 average;
1945 u8 max_pwr;
1946 s16 desired_pwr, estimated_pwr, pwr_adjust;
1947 s16 radio_att_delta, baseband_att_delta;
1948 s16 radio_attenuation, baseband_attenuation;
1949 unsigned long phylock_flags;
1950
1951 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058);
1952 v0 = (s8)(tmp & 0x00FF);
1953 v1 = (s8)((tmp & 0xFF00) >> 8);
1954 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A);
1955 v2 = (s8)(tmp & 0x00FF);
1956 v3 = (s8)((tmp & 0xFF00) >> 8);
1957 tmp = 0;
1958
1959 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
1960 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070);
1961 v0 = (s8)(tmp & 0x00FF);
1962 v1 = (s8)((tmp & 0xFF00) >> 8);
1963 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072);
1964 v2 = (s8)(tmp & 0x00FF);
1965 v3 = (s8)((tmp & 0xFF00) >> 8);
1966 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
1967 return;
1968 v0 = (v0 + 0x20) & 0x3F;
1969 v1 = (v1 + 0x20) & 0x3F;
1970 v2 = (v2 + 0x20) & 0x3F;
1971 v3 = (v3 + 0x20) & 0x3F;
1972 tmp = 1;
1973 }
1974 bcm43xx_radio_clear_tssi(bcm);
1975
1976 average = (v0 + v1 + v2 + v3 + 2) / 4;
1977
1978 if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8))
1979 average -= 13;
1980
1981 estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average);
1982
1983 max_pwr = bcm->sprom.maxpower_bgphy;
1984
1985 if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) &&
1986 (phy->type == BCM43xx_PHYTYPE_G))
1987 max_pwr -= 0x3;
1988
1989 /*TODO:
1990 max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr)
1991 where REG is the max power as per the regulatory domain
1992 */
1993
1994 desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr);
1995 /* Check if we need to adjust the current power. */
1996 pwr_adjust = desired_pwr - estimated_pwr;
1997 radio_att_delta = -(pwr_adjust + 7) >> 3;
1998 baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
1999 if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
2000 bcm43xx_phy_lo_mark_current_used(bcm);
2001 return;
2002 }
2003
2004 /* Calculate the new attenuation values. */
2005 baseband_attenuation = radio->baseband_atten;
2006 baseband_attenuation += baseband_att_delta;
2007 radio_attenuation = radio->radio_atten;
2008 radio_attenuation += radio_att_delta;
2009
2010 /* Get baseband and radio attenuation values into their permitted ranges.
2011 * baseband 0-11, radio 0-9.
2012 * Radio attenuation affects power level 4 times as much as baseband.
2013 */
2014 if (radio_attenuation < 0) {
2015 baseband_attenuation -= (4 * -radio_attenuation);
2016 radio_attenuation = 0;
2017 } else if (radio_attenuation > 9) {
2018 baseband_attenuation += (4 * (radio_attenuation - 9));
2019 radio_attenuation = 9;
2020 } else {
2021 while (baseband_attenuation < 0 && radio_attenuation > 0) {
2022 baseband_attenuation += 4;
2023 radio_attenuation--;
2024 }
2025 while (baseband_attenuation > 11 && radio_attenuation < 9) {
2026 baseband_attenuation -= 4;
2027 radio_attenuation++;
2028 }
2029 }
2030 baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
2031
2032 txpower = radio->txctl1;
2033 if ((radio->version == 0x2050) && (radio->revision == 2)) {
2034 if (radio_attenuation <= 1) {
2035 if (txpower == 0) {
2036 txpower = 3;
2037 radio_attenuation += 2;
2038 baseband_attenuation += 2;
2039 } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
2040 baseband_attenuation += 4 * (radio_attenuation - 2);
2041 radio_attenuation = 2;
2042 }
2043 } else if (radio_attenuation > 4 && txpower != 0) {
2044 txpower = 0;
2045 if (baseband_attenuation < 3) {
2046 radio_attenuation -= 3;
2047 baseband_attenuation += 2;
2048 } else {
2049 radio_attenuation -= 2;
2050 baseband_attenuation -= 2;
2051 }
2052 }
2053 }
2054 radio->txctl1 = txpower;
2055 baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
2056 radio_attenuation = limit_value(radio_attenuation, 0, 9);
2057
2058 bcm43xx_phy_lock(bcm, phylock_flags);
2059 bcm43xx_radio_lock(bcm);
2060 bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation,
2061 radio_attenuation, txpower);
2062 bcm43xx_phy_lo_mark_current_used(bcm);
2063 bcm43xx_radio_unlock(bcm);
2064 bcm43xx_phy_unlock(bcm, phylock_flags);
2065 break;
2066 }
2067 default:
2068 assert(0);
2069 }
2070}
2071
2072static inline
2073s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den)
2074{
2075 if (num < 0)
2076 return num/den;
2077 else
2078 return (num+den/2)/den;
2079}
2080
2081static inline
2082s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
2083{
2084 s32 m1, m2, f = 256, q, delta;
2085 s8 i = 0;
2086
2087 m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
2088 m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1);
2089 do {
2090 if (i > 15)
2091 return -EINVAL;
2092 q = bcm43xx_tssi2dbm_ad(f * 4096 -
2093 bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048);
2094 delta = abs(q - f);
2095 f = q;
2096 i++;
2097 } while (delta >= 2);
2098 entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128);
2099 return 0;
2100}
2101
2102/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
2103int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm)
2104{
2105 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2106 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
2107 s16 pab0, pab1, pab2;
2108 u8 idx;
2109 s8 *dyn_tssi2dbm;
2110
2111 if (phy->type == BCM43xx_PHYTYPE_A) {
2112 pab0 = (s16)(bcm->sprom.pa1b0);
2113 pab1 = (s16)(bcm->sprom.pa1b1);
2114 pab2 = (s16)(bcm->sprom.pa1b2);
2115 } else {
2116 pab0 = (s16)(bcm->sprom.pa0b0);
2117 pab1 = (s16)(bcm->sprom.pa0b1);
2118 pab2 = (s16)(bcm->sprom.pa0b2);
2119 }
2120
2121 if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) {
2122 phy->idle_tssi = 0x34;
2123 phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
2124 return 0;
2125 }
2126
2127 if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
2128 pab0 != -1 && pab1 != -1 && pab2 != -1) {
2129 /* The pabX values are set in SPROM. Use them. */
2130 if (phy->type == BCM43xx_PHYTYPE_A) {
2131 if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 &&
2132 (s8)bcm->sprom.idle_tssi_tgt_aphy != -1)
2133 phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy);
2134 else
2135 phy->idle_tssi = 62;
2136 } else {
2137 if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 &&
2138 (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1)
2139 phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy);
2140 else
2141 phy->idle_tssi = 62;
2142 }
2143 dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
2144 if (dyn_tssi2dbm == NULL) {
2145 printk(KERN_ERR PFX "Could not allocate memory"
2146 "for tssi2dbm table\n");
2147 return -ENOMEM;
2148 }
2149 for (idx = 0; idx < 64; idx++)
2150 if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
2151 phy->tssi2dbm = NULL;
2152 printk(KERN_ERR PFX "Could not generate "
2153 "tssi2dBm table\n");
2154 return -ENODEV;
2155 }
2156 phy->tssi2dbm = dyn_tssi2dbm;
2157 phy->dyn_tssi_tbl = 1;
2158 } else {
2159 /* pabX values not set in SPROM. */
2160 switch (phy->type) {
2161 case BCM43xx_PHYTYPE_A:
2162 /* APHY needs a generated table. */
2163 phy->tssi2dbm = NULL;
2164 printk(KERN_ERR PFX "Could not generate tssi2dBm "
2165 "table (wrong SPROM info)!\n");
2166 return -ENODEV;
2167 case BCM43xx_PHYTYPE_B:
2168 phy->idle_tssi = 0x34;
2169 phy->tssi2dbm = bcm43xx_tssi2dbm_b_table;
2170 break;
2171 case BCM43xx_PHYTYPE_G:
2172 phy->idle_tssi = 0x34;
2173 phy->tssi2dbm = bcm43xx_tssi2dbm_g_table;
2174 break;
2175 }
2176 }
2177
2178 return 0;
2179}
2180
2181int bcm43xx_phy_init(struct bcm43xx_private *bcm)
2182{
2183 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2184 int err = -ENODEV;
2185 unsigned long flags;
2186
2187 /* We do not want to be preempted while calibrating
2188 * the hardware.
2189 */
2190 local_irq_save(flags);
2191
2192 switch (phy->type) {
2193 case BCM43xx_PHYTYPE_A:
2194 if (phy->rev == 2 || phy->rev == 3) {
2195 bcm43xx_phy_inita(bcm);
2196 err = 0;
2197 }
2198 break;
2199 case BCM43xx_PHYTYPE_B:
2200 switch (phy->rev) {
2201 case 2:
2202 bcm43xx_phy_initb2(bcm);
2203 err = 0;
2204 break;
2205 case 4:
2206 bcm43xx_phy_initb4(bcm);
2207 err = 0;
2208 break;
2209 case 5:
2210 bcm43xx_phy_initb5(bcm);
2211 err = 0;
2212 break;
2213 case 6:
2214 bcm43xx_phy_initb6(bcm);
2215 err = 0;
2216 break;
2217 }
2218 break;
2219 case BCM43xx_PHYTYPE_G:
2220 bcm43xx_phy_initg(bcm);
2221 err = 0;
2222 break;
2223 }
2224 local_irq_restore(flags);
2225 if (err)
2226 printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
2227
2228 return err;
2229}
2230
2231void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm)
2232{
2233 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2234 u16 antennadiv;
2235 u16 offset;
2236 u16 value;
2237 u32 ucodeflags;
2238
2239 antennadiv = phy->antenna_diversity;
2240
2241 if (antennadiv == 0xFFFF)
2242 antennadiv = 3;
2243 assert(antennadiv <= 3);
2244
2245 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2246 BCM43xx_UCODEFLAGS_OFFSET);
2247 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2248 BCM43xx_UCODEFLAGS_OFFSET,
2249 ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV);
2250
2251 switch (phy->type) {
2252 case BCM43xx_PHYTYPE_A:
2253 case BCM43xx_PHYTYPE_G:
2254 if (phy->type == BCM43xx_PHYTYPE_A)
2255 offset = 0x0000;
2256 else
2257 offset = 0x0400;
2258
2259 if (antennadiv == 2)
2260 value = (3/*automatic*/ << 7);
2261 else
2262 value = (antennadiv << 7);
2263 bcm43xx_phy_write(bcm, offset + 1,
2264 (bcm43xx_phy_read(bcm, offset + 1)
2265 & 0x7E7F) | value);
2266
2267 if (antennadiv >= 2) {
2268 if (antennadiv == 2)
2269 value = (antennadiv << 7);
2270 else
2271 value = (0/*force0*/ << 7);
2272 bcm43xx_phy_write(bcm, offset + 0x2B,
2273 (bcm43xx_phy_read(bcm, offset + 0x2B)
2274 & 0xFEFF) | value);
2275 }
2276
2277 if (phy->type == BCM43xx_PHYTYPE_G) {
2278 if (antennadiv >= 2)
2279 bcm43xx_phy_write(bcm, 0x048C,
2280 bcm43xx_phy_read(bcm, 0x048C)
2281 | 0x2000);
2282 else
2283 bcm43xx_phy_write(bcm, 0x048C,
2284 bcm43xx_phy_read(bcm, 0x048C)
2285 & ~0x2000);
2286 if (phy->rev >= 2) {
2287 bcm43xx_phy_write(bcm, 0x0461,
2288 bcm43xx_phy_read(bcm, 0x0461)
2289 | 0x0010);
2290 bcm43xx_phy_write(bcm, 0x04AD,
2291 (bcm43xx_phy_read(bcm, 0x04AD)
2292 & 0x00FF) | 0x0015);
2293 if (phy->rev == 2)
2294 bcm43xx_phy_write(bcm, 0x0427, 0x0008);
2295 else
2296 bcm43xx_phy_write(bcm, 0x0427,
2297 (bcm43xx_phy_read(bcm, 0x0427)
2298 & 0x00FF) | 0x0008);
2299 }
2300 else if (phy->rev >= 6)
2301 bcm43xx_phy_write(bcm, 0x049B, 0x00DC);
2302 } else {
2303 if (phy->rev < 3)
2304 bcm43xx_phy_write(bcm, 0x002B,
2305 (bcm43xx_phy_read(bcm, 0x002B)
2306 & 0x00FF) | 0x0024);
2307 else {
2308 bcm43xx_phy_write(bcm, 0x0061,
2309 bcm43xx_phy_read(bcm, 0x0061)
2310 | 0x0010);
2311 if (phy->rev == 3) {
2312 bcm43xx_phy_write(bcm, 0x0093, 0x001D);
2313 bcm43xx_phy_write(bcm, 0x0027, 0x0008);
2314 } else {
2315 bcm43xx_phy_write(bcm, 0x0093, 0x003A);
2316 bcm43xx_phy_write(bcm, 0x0027,
2317 (bcm43xx_phy_read(bcm, 0x0027)
2318 & 0x00FF) | 0x0008);
2319 }
2320 }
2321 }
2322 break;
2323 case BCM43xx_PHYTYPE_B:
2324 if (bcm->current_core->rev == 2)
2325 value = (3/*automatic*/ << 7);
2326 else
2327 value = (antennadiv << 7);
2328 bcm43xx_phy_write(bcm, 0x03E2,
2329 (bcm43xx_phy_read(bcm, 0x03E2)
2330 & 0xFE7F) | value);
2331 break;
2332 default:
2333 assert(0);
2334 }
2335
2336 if (antennadiv >= 2) {
2337 ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
2338 BCM43xx_UCODEFLAGS_OFFSET);
2339 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
2340 BCM43xx_UCODEFLAGS_OFFSET,
2341 ucodeflags | BCM43xx_UCODEFLAG_AUTODIV);
2342 }
2343
2344 phy->antenna_diversity = antennadiv;
2345}
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..c59ddd40680d
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -0,0 +1,606 @@
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#include "bcm43xx_xmit.h"
30
31#include <linux/delay.h>
32
33
34static void tx_start(struct bcm43xx_pioqueue *queue)
35{
36 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
37 BCM43xx_PIO_TXCTL_INIT);
38}
39
40static void tx_octet(struct bcm43xx_pioqueue *queue,
41 u8 octet)
42{
43 if (queue->need_workarounds) {
44 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
45 octet);
46 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
47 BCM43xx_PIO_TXCTL_WRITEHI);
48 } else {
49 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
50 BCM43xx_PIO_TXCTL_WRITEHI);
51 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
52 octet);
53 }
54}
55
56static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr,
57 const u8 *packet,
58 unsigned int *pos)
59{
60 const u8 *source;
61 unsigned int i = *pos;
62 u16 ret;
63
64 if (i < sizeof(*txhdr)) {
65 source = (const u8 *)txhdr;
66 } else {
67 source = packet;
68 i -= sizeof(*txhdr);
69 }
70 ret = le16_to_cpu( *((u16 *)(source + i)) );
71 *pos += 2;
72
73 return ret;
74}
75
76static void tx_data(struct bcm43xx_pioqueue *queue,
77 struct bcm43xx_txhdr *txhdr,
78 const u8 *packet,
79 unsigned int octets)
80{
81 u16 data;
82 unsigned int i = 0;
83
84 if (queue->need_workarounds) {
85 data = tx_get_next_word(txhdr, packet, &i);
86 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
87 }
88 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
89 BCM43xx_PIO_TXCTL_WRITELO |
90 BCM43xx_PIO_TXCTL_WRITEHI);
91 while (i < octets - 1) {
92 data = tx_get_next_word(txhdr, packet, &i);
93 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
94 }
95 if (octets % 2)
96 tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]);
97}
98
99static void tx_complete(struct bcm43xx_pioqueue *queue,
100 struct sk_buff *skb)
101{
102 if (queue->need_workarounds) {
103 bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
104 skb->data[skb->len - 1]);
105 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
106 BCM43xx_PIO_TXCTL_WRITEHI |
107 BCM43xx_PIO_TXCTL_COMPLETE);
108 } else {
109 bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
110 BCM43xx_PIO_TXCTL_COMPLETE);
111 }
112}
113
114static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
115 int packetindex)
116{
117 u16 cookie = 0x0000;
118
119 /* We use the upper 4 bits for the PIO
120 * controller ID and the lower 12 bits
121 * for the packet index (in the cache).
122 */
123 switch (queue->mmio_base) {
124 case BCM43xx_MMIO_PIO1_BASE:
125 break;
126 case BCM43xx_MMIO_PIO2_BASE:
127 cookie = 0x1000;
128 break;
129 case BCM43xx_MMIO_PIO3_BASE:
130 cookie = 0x2000;
131 break;
132 case BCM43xx_MMIO_PIO4_BASE:
133 cookie = 0x3000;
134 break;
135 default:
136 assert(0);
137 }
138 assert(((u16)packetindex & 0xF000) == 0x0000);
139 cookie |= (u16)packetindex;
140
141 return cookie;
142}
143
144static
145struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm,
146 u16 cookie,
147 struct bcm43xx_pio_txpacket **packet)
148{
149 struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);
150 struct bcm43xx_pioqueue *queue = NULL;
151 int packetindex;
152
153 switch (cookie & 0xF000) {
154 case 0x0000:
155 queue = pio->queue0;
156 break;
157 case 0x1000:
158 queue = pio->queue1;
159 break;
160 case 0x2000:
161 queue = pio->queue2;
162 break;
163 case 0x3000:
164 queue = pio->queue3;
165 break;
166 default:
167 assert(0);
168 }
169 packetindex = (cookie & 0x0FFF);
170 assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS);
171 *packet = &(queue->tx_packets_cache[packetindex]);
172
173 return queue;
174}
175
176static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
177 struct sk_buff *skb,
178 struct bcm43xx_pio_txpacket *packet)
179{
180 struct bcm43xx_txhdr txhdr;
181 unsigned int octets;
182
183 assert(skb_shinfo(skb)->nr_frags == 0);
184 bcm43xx_generate_txhdr(queue->bcm,
185 &txhdr, skb->data, skb->len,
186 (packet->xmitted_frags == 0),
187 generate_cookie(queue, pio_txpacket_getindex(packet)));
188
189 tx_start(queue);
190 octets = skb->len + sizeof(txhdr);
191 if (queue->need_workarounds)
192 octets--;
193 tx_data(queue, &txhdr, (u8 *)skb->data, octets);
194 tx_complete(queue, skb);
195}
196
197static void free_txpacket(struct bcm43xx_pio_txpacket *packet,
198 int irq_context)
199{
200 struct bcm43xx_pioqueue *queue = packet->queue;
201
202 ieee80211_txb_free(packet->txb);
203 list_move(&packet->list, &queue->txfree);
204 queue->nr_txfree++;
205
206 assert(queue->tx_devq_used >= packet->xmitted_octets);
207 assert(queue->tx_devq_packets >= packet->xmitted_frags);
208 queue->tx_devq_used -= packet->xmitted_octets;
209 queue->tx_devq_packets -= packet->xmitted_frags;
210}
211
212static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
213{
214 struct bcm43xx_pioqueue *queue = packet->queue;
215 struct ieee80211_txb *txb = packet->txb;
216 struct sk_buff *skb;
217 u16 octets;
218 int i;
219
220 for (i = packet->xmitted_frags; i < txb->nr_frags; i++) {
221 skb = txb->fragments[i];
222
223 octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr);
224 assert(queue->tx_devq_size >= octets);
225 assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS);
226 assert(queue->tx_devq_used <= queue->tx_devq_size);
227 /* Check if there is sufficient free space on the device
228 * TX queue. If not, return and let the TX tasklet
229 * retry later.
230 */
231 if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS)
232 return -EBUSY;
233 if (queue->tx_devq_used + octets > queue->tx_devq_size)
234 return -EBUSY;
235 /* Now poke the device. */
236 pio_tx_write_fragment(queue, skb, packet);
237
238 /* Account for the packet size.
239 * (We must not overflow the device TX queue)
240 */
241 queue->tx_devq_packets++;
242 queue->tx_devq_used += octets;
243
244 assert(packet->xmitted_frags <= packet->txb->nr_frags);
245 packet->xmitted_frags++;
246 packet->xmitted_octets += octets;
247 }
248 list_move_tail(&packet->list, &queue->txrunning);
249
250 return 0;
251}
252
253static void tx_tasklet(unsigned long d)
254{
255 struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d;
256 struct bcm43xx_private *bcm = queue->bcm;
257 unsigned long flags;
258 struct bcm43xx_pio_txpacket *packet, *tmp_packet;
259 int err;
260
261 bcm43xx_lock_mmio(bcm, flags);
262 list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
263 assert(packet->xmitted_frags < packet->txb->nr_frags);
264 if (packet->xmitted_frags == 0) {
265 int i;
266 struct sk_buff *skb;
267
268 /* Check if the device queue is big
269 * enough for every fragment. If not, drop the
270 * whole packet.
271 */
272 for (i = 0; i < packet->txb->nr_frags; i++) {
273 skb = packet->txb->fragments[i];
274 if (unlikely(skb->len > queue->tx_devq_size)) {
275 dprintkl(KERN_ERR PFX "PIO TX device queue too small. "
276 "Dropping packet.\n");
277 free_txpacket(packet, 1);
278 goto next_packet;
279 }
280 }
281 }
282 /* Try to transmit the packet.
283 * This may not completely succeed.
284 */
285 err = pio_tx_packet(packet);
286 if (err)
287 break;
288 next_packet:
289 continue;
290 }
291 bcm43xx_unlock_mmio(bcm, flags);
292}
293
294static void setup_txqueues(struct bcm43xx_pioqueue *queue)
295{
296 struct bcm43xx_pio_txpacket *packet;
297 int i;
298
299 queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS;
300 for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) {
301 packet = &(queue->tx_packets_cache[i]);
302
303 packet->queue = queue;
304 INIT_LIST_HEAD(&packet->list);
305
306 list_add(&packet->list, &queue->txfree);
307 }
308}
309
310static
311struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,
312 u16 pio_mmio_base)
313{
314 struct bcm43xx_pioqueue *queue;
315 u32 value;
316 u16 qsize;
317
318 queue = kzalloc(sizeof(*queue), GFP_KERNEL);
319 if (!queue)
320 goto out;
321
322 queue->bcm = bcm;
323 queue->mmio_base = pio_mmio_base;
324 queue->need_workarounds = (bcm->current_core->rev < 3);
325
326 INIT_LIST_HEAD(&queue->txfree);
327 INIT_LIST_HEAD(&queue->txqueue);
328 INIT_LIST_HEAD(&queue->txrunning);
329 tasklet_init(&queue->txtask, tx_tasklet,
330 (unsigned long)queue);
331
332 value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
333 value |= BCM43xx_SBF_XFER_REG_BYTESWAP;
334 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
335
336 qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
337 if (qsize <= BCM43xx_PIO_TXQADJUST) {
338 printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize);
339 goto err_freequeue;
340 }
341 qsize -= BCM43xx_PIO_TXQADJUST;
342 queue->tx_devq_size = qsize;
343
344 setup_txqueues(queue);
345
346out:
347 return queue;
348
349err_freequeue:
350 kfree(queue);
351 queue = NULL;
352 goto out;
353}
354
355static void cancel_transfers(struct bcm43xx_pioqueue *queue)
356{
357 struct bcm43xx_pio_txpacket *packet, *tmp_packet;
358
359 netif_tx_disable(queue->bcm->net_dev);
360 assert(queue->bcm->shutting_down);
361 tasklet_disable(&queue->txtask);
362
363 list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
364 free_txpacket(packet, 0);
365 list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
366 free_txpacket(packet, 0);
367}
368
369static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue)
370{
371 if (!queue)
372 return;
373
374 cancel_transfers(queue);
375 kfree(queue);
376}
377
378void bcm43xx_pio_free(struct bcm43xx_private *bcm)
379{
380 struct bcm43xx_pio *pio;
381
382 if (!bcm43xx_using_pio(bcm))
383 return;
384 pio = bcm43xx_current_pio(bcm);
385
386 bcm43xx_destroy_pioqueue(pio->queue3);
387 pio->queue3 = NULL;
388 bcm43xx_destroy_pioqueue(pio->queue2);
389 pio->queue2 = NULL;
390 bcm43xx_destroy_pioqueue(pio->queue1);
391 pio->queue1 = NULL;
392 bcm43xx_destroy_pioqueue(pio->queue0);
393 pio->queue0 = NULL;
394}
395
396int bcm43xx_pio_init(struct bcm43xx_private *bcm)
397{
398 struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm);
399 struct bcm43xx_pioqueue *queue;
400 int err = -ENOMEM;
401
402 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE);
403 if (!queue)
404 goto out;
405 pio->queue0 = queue;
406
407 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE);
408 if (!queue)
409 goto err_destroy0;
410 pio->queue1 = queue;
411
412 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE);
413 if (!queue)
414 goto err_destroy1;
415 pio->queue2 = queue;
416
417 queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE);
418 if (!queue)
419 goto err_destroy2;
420 pio->queue3 = queue;
421
422 if (bcm->current_core->rev < 3)
423 bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND;
424
425 dprintk(KERN_INFO PFX "PIO initialized\n");
426 err = 0;
427out:
428 return err;
429
430err_destroy2:
431 bcm43xx_destroy_pioqueue(pio->queue2);
432 pio->queue2 = NULL;
433err_destroy1:
434 bcm43xx_destroy_pioqueue(pio->queue1);
435 pio->queue1 = NULL;
436err_destroy0:
437 bcm43xx_destroy_pioqueue(pio->queue0);
438 pio->queue0 = NULL;
439 goto out;
440}
441
442int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
443 struct ieee80211_txb *txb)
444{
445 struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1;
446 struct bcm43xx_pio_txpacket *packet;
447 u16 tmp;
448
449 assert(!queue->tx_suspended);
450 assert(!list_empty(&queue->txfree));
451
452 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
453 if (tmp & BCM43xx_PIO_TXCTL_SUSPEND)
454 return -EBUSY;
455
456 packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
457 packet->txb = txb;
458 packet->xmitted_frags = 0;
459 packet->xmitted_octets = 0;
460 list_move_tail(&packet->list, &queue->txqueue);
461 queue->nr_txfree--;
462 assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS);
463
464 /* Suspend TX, if we are out of packets in the "free" queue. */
465 if (unlikely(list_empty(&queue->txfree))) {
466 netif_stop_queue(queue->bcm->net_dev);
467 queue->tx_suspended = 1;
468 }
469
470 tasklet_schedule(&queue->txtask);
471
472 return 0;
473}
474
475void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
476 struct bcm43xx_xmitstatus *status)
477{
478 struct bcm43xx_pioqueue *queue;
479 struct bcm43xx_pio_txpacket *packet;
480
481 queue = parse_cookie(bcm, status->cookie, &packet);
482 assert(queue);
483//TODO
484if (!queue)
485return;
486 free_txpacket(packet, 1);
487 if (unlikely(queue->tx_suspended)) {
488 queue->tx_suspended = 0;
489 netif_wake_queue(queue->bcm->net_dev);
490 }
491 /* If there are packets on the txqueue, poke the tasklet. */
492 if (!list_empty(&queue->txqueue))
493 tasklet_schedule(&queue->txtask);
494}
495
496static void pio_rx_error(struct bcm43xx_pioqueue *queue,
497 int clear_buffers,
498 const char *error)
499{
500 int i;
501
502 printkl("PIO RX error: %s\n", error);
503 bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
504 BCM43xx_PIO_RXCTL_READY);
505 if (clear_buffers) {
506 assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE);
507 for (i = 0; i < 15; i++) {
508 /* Dummy read. */
509 bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
510 }
511 }
512}
513
514void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
515{
516 u16 preamble[21] = { 0 };
517 struct bcm43xx_rxhdr *rxhdr;
518 u16 tmp, len, rxflags2;
519 int i, preamble_readwords;
520 struct sk_buff *skb;
521
522return;
523 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
524 if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) {
525 dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk.
526 return;
527 }
528 bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
529 BCM43xx_PIO_RXCTL_DATAAVAILABLE);
530
531 for (i = 0; i < 10; i++) {
532 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
533 if (tmp & BCM43xx_PIO_RXCTL_READY)
534 goto data_ready;
535 udelay(10);
536 }
537 dprintkl(KERN_ERR PFX "PIO RX timed out\n");
538 return;
539data_ready:
540
541//FIXME: endianess in this function.
542 len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
543 if (unlikely(len > 0x700)) {
544 pio_rx_error(queue, 0, "len > 0x700");
545 return;
546 }
547 if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) {
548 pio_rx_error(queue, 0, "len == 0");
549 return;
550 }
551 preamble[0] = cpu_to_le16(len);
552 if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE)
553 preamble_readwords = 14 / sizeof(u16);
554 else
555 preamble_readwords = 18 / sizeof(u16);
556 for (i = 0; i < preamble_readwords; i++) {
557 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
558 preamble[i + 1] = cpu_to_be16(tmp);//FIXME?
559 }
560 rxhdr = (struct bcm43xx_rxhdr *)preamble;
561 rxflags2 = le16_to_cpu(rxhdr->flags2);
562 if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) {
563 pio_rx_error(queue,
564 (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE),
565 "invalid frame");
566 return;
567 }
568 if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) {
569 /* We received an xmit status. */
570 struct bcm43xx_hwxmitstatus *hw;
571 struct bcm43xx_xmitstatus stat;
572
573 hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1);
574 stat.cookie = le16_to_cpu(hw->cookie);
575 stat.flags = hw->flags;
576 stat.cnt1 = hw->cnt1;
577 stat.cnt2 = hw->cnt2;
578 stat.seq = le16_to_cpu(hw->seq);
579 stat.unknown = le16_to_cpu(hw->unknown);
580
581 bcm43xx_debugfs_log_txstat(queue->bcm, &stat);
582 bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat);
583
584 return;
585 }
586
587 skb = dev_alloc_skb(len);
588 if (unlikely(!skb)) {
589 pio_rx_error(queue, 1, "OOM");
590 return;
591 }
592 skb_put(skb, len);
593 for (i = 0; i < len - 1; i += 2) {
594 tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
595 *((u16 *)(skb->data + i)) = tmp;
596 }
597 if (len % 2) {
598 tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
599 skb->data[len - 1] = (tmp & 0x00FF);
600 if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
601 skb->data[0x20] = (tmp & 0xFF00) >> 8;
602 else
603 skb->data[0x1E] = (tmp & 0xFF00) >> 8;
604 }
605 bcm43xx_rx(queue->bcm, skb, rxhdr);
606}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
new file mode 100644
index 000000000000..970627bc1769
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -0,0 +1,138 @@
1#ifndef BCM43xx_PIO_H_
2#define BCM43xx_PIO_H_
3
4#include "bcm43xx.h"
5
6#include <linux/interrupt.h>
7#include <linux/list.h>
8#include <linux/skbuff.h>
9
10
11#define BCM43xx_PIO_TXCTL 0x00
12#define BCM43xx_PIO_TXDATA 0x02
13#define BCM43xx_PIO_TXQBUFSIZE 0x04
14#define BCM43xx_PIO_RXCTL 0x08
15#define BCM43xx_PIO_RXDATA 0x0A
16
17#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0)
18#define BCM43xx_PIO_TXCTL_WRITELO (1 << 1)
19#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2)
20#define BCM43xx_PIO_TXCTL_INIT (1 << 3)
21#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7)
22
23#define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0)
24#define BCM43xx_PIO_RXCTL_READY (1 << 1)
25
26/* PIO constants */
27#define BCM43xx_PIO_MAXTXDEVQPACKETS 31
28#define BCM43xx_PIO_TXQADJUST 80
29
30/* PIO tuning knobs */
31#define BCM43xx_PIO_MAXTXPACKETS 256
32
33
34
35#ifdef CONFIG_BCM43XX_PIO
36
37
38struct bcm43xx_pioqueue;
39struct bcm43xx_xmitstatus;
40
41struct bcm43xx_pio_txpacket {
42 struct bcm43xx_pioqueue *queue;
43 struct ieee80211_txb *txb;
44 struct list_head list;
45
46 u8 xmitted_frags;
47 u16 xmitted_octets;
48};
49
50#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache))
51
52struct bcm43xx_pioqueue {
53 struct bcm43xx_private *bcm;
54 u16 mmio_base;
55
56 u8 tx_suspended:1,
57 need_workarounds:1; /* Workarounds needed for core.rev < 3 */
58
59 /* Adjusted size of the device internal TX buffer. */
60 u16 tx_devq_size;
61 /* Used octets of the device internal TX buffer. */
62 u16 tx_devq_used;
63 /* Used packet slots in the device internal TX buffer. */
64 u8 tx_devq_packets;
65 /* Packets from the txfree list can
66 * be taken on incoming TX requests.
67 */
68 struct list_head txfree;
69 unsigned int nr_txfree;
70 /* Packets on the txqueue are queued,
71 * but not completely written to the chip, yet.
72 */
73 struct list_head txqueue;
74 /* Packets on the txrunning queue are completely
75 * posted to the device. We are waiting for the txstatus.
76 */
77 struct list_head txrunning;
78 /* Total number or packets sent.
79 * (This counter can obviously wrap).
80 */
81 unsigned int nr_tx_packets;
82 struct tasklet_struct txtask;
83 struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS];
84};
85
86static inline
87u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue,
88 u16 offset)
89{
90 return bcm43xx_read16(queue->bcm, queue->mmio_base + offset);
91}
92
93static inline
94void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
95 u16 offset, u16 value)
96{
97 bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
98}
99
100
101int bcm43xx_pio_init(struct bcm43xx_private *bcm);
102void bcm43xx_pio_free(struct bcm43xx_private *bcm);
103
104int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
105 struct ieee80211_txb *txb);
106void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
107 struct bcm43xx_xmitstatus *status);
108void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
109
110#else /* CONFIG_BCM43XX_PIO */
111
112static inline
113int bcm43xx_pio_init(struct bcm43xx_private *bcm)
114{
115 return 0;
116}
117static inline
118void bcm43xx_pio_free(struct bcm43xx_private *bcm)
119{
120}
121static inline
122int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
123 struct ieee80211_txb *txb)
124{
125 return 0;
126}
127static inline
128void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
129 struct bcm43xx_xmitstatus *status)
130{
131}
132static inline
133void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
134{
135}
136
137#endif /* CONFIG_BCM43XX_PIO */
138#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..af5c0bff1696
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -0,0 +1,2026 @@
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 mmiowb();
101 udelay(10);
102}
103
104void bcm43xx_radio_unlock(struct bcm43xx_private *bcm)
105{
106 u32 status;
107
108 bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */
109 status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
110 status &= ~BCM43xx_SBF_RADIOREG_LOCK;
111 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
112 mmiowb();
113}
114
115u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset)
116{
117 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
118 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
119
120 switch (phy->type) {
121 case BCM43xx_PHYTYPE_A:
122 offset |= 0x0040;
123 break;
124 case BCM43xx_PHYTYPE_B:
125 if (radio->version == 0x2053) {
126 if (offset < 0x70)
127 offset += 0x80;
128 else if (offset < 0x80)
129 offset += 0x70;
130 } else if (radio->version == 0x2050) {
131 offset |= 0x80;
132 } else
133 assert(0);
134 break;
135 case BCM43xx_PHYTYPE_G:
136 offset |= 0x80;
137 break;
138 }
139
140 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
141 return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
142}
143
144void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val)
145{
146 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
147 mmiowb();
148 bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val);
149}
150
151static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm,
152 s16 first, s16 second, s16 third)
153{
154 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
155 u16 i;
156 u16 start = 0x08, end = 0x18;
157 u16 offset = 0x0400;
158 u16 tmp;
159
160 if (phy->rev <= 1) {
161 offset = 0x5000;
162 start = 0x10;
163 end = 0x20;
164 }
165
166 for (i = 0; i < 4; i++)
167 bcm43xx_ilt_write(bcm, offset + i, first);
168
169 for (i = start; i < end; i++)
170 bcm43xx_ilt_write(bcm, offset + i, second);
171
172 if (third != -1) {
173 tmp = ((u16)third << 14) | ((u16)third << 6);
174 bcm43xx_phy_write(bcm, 0x04A0,
175 (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp);
176 bcm43xx_phy_write(bcm, 0x04A1,
177 (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp);
178 bcm43xx_phy_write(bcm, 0x04A2,
179 (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp);
180 }
181 bcm43xx_dummy_transmission(bcm);
182}
183
184static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm)
185{
186 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
187 u16 i, tmp;
188 u16 offset = 0x0400;
189 u16 start = 0x0008, end = 0x0018;
190
191 if (phy->rev <= 1) {
192 offset = 0x5000;
193 start = 0x0010;
194 end = 0x0020;
195 }
196
197 for (i = 0; i < 4; i++) {
198 tmp = (i & 0xFFFC);
199 tmp |= (i & 0x0001) << 1;
200 tmp |= (i & 0x0002) >> 1;
201
202 bcm43xx_ilt_write(bcm, offset + i, tmp);
203 }
204
205 for (i = start; i < end; i++)
206 bcm43xx_ilt_write(bcm, offset + i, i - start);
207
208 bcm43xx_phy_write(bcm, 0x04A0,
209 (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040);
210 bcm43xx_phy_write(bcm, 0x04A1,
211 (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040);
212 bcm43xx_phy_write(bcm, 0x04A2,
213 (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000);
214 bcm43xx_dummy_transmission(bcm);
215}
216
217/* Synthetic PU workaround */
218static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel)
219{
220 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
221
222 if (radio->version != 0x2050 || radio->revision >= 6) {
223 /* We do not need the workaround. */
224 return;
225 }
226
227 if (channel <= 10) {
228 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
229 channel2freq_bg(channel + 4));
230 } else {
231 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
232 channel2freq_bg(1));
233 }
234 udelay(100);
235 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
236 channel2freq_bg(channel));
237}
238
239u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel)
240{
241 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
242 u8 ret = 0;
243 u16 saved, rssi, temp;
244 int i, j = 0;
245
246 saved = bcm43xx_phy_read(bcm, 0x0403);
247 bcm43xx_radio_selectchannel(bcm, channel, 0);
248 bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5);
249 if (radio->aci_hw_rssi)
250 rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F;
251 else
252 rssi = saved & 0x3F;
253 /* clamp temp to signed 5bit */
254 if (rssi > 32)
255 rssi -= 64;
256 for (i = 0;i < 100; i++) {
257 temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F;
258 if (temp > 32)
259 temp -= 64;
260 if (temp < rssi)
261 j++;
262 if (j >= 20)
263 ret = 1;
264 }
265 bcm43xx_phy_write(bcm, 0x0403, saved);
266
267 return ret;
268}
269
270u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm)
271{
272 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
273 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
274 u8 ret[13];
275 unsigned int channel = radio->channel;
276 unsigned int i, j, start, end;
277 unsigned long phylock_flags;
278
279 if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0)))
280 return 0;
281
282 bcm43xx_phy_lock(bcm, phylock_flags);
283 bcm43xx_radio_lock(bcm);
284 bcm43xx_phy_write(bcm, 0x0802,
285 bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
286 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
287 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
288 bcm43xx_set_all_gains(bcm, 3, 8, 1);
289
290 start = (channel - 5 > 0) ? channel - 5 : 1;
291 end = (channel + 5 < 14) ? channel + 5 : 13;
292
293 for (i = start; i <= end; i++) {
294 if (abs(channel - i) > 2)
295 ret[i-1] = bcm43xx_radio_aci_detect(bcm, i);
296 }
297 bcm43xx_radio_selectchannel(bcm, channel, 0);
298 bcm43xx_phy_write(bcm, 0x0802,
299 (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003);
300 bcm43xx_phy_write(bcm, 0x0403,
301 bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8);
302 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
303 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
304 bcm43xx_set_original_gains(bcm);
305 for (i = 0; i < 13; i++) {
306 if (!ret[i])
307 continue;
308 end = (i + 5 < 13) ? i + 5 : 13;
309 for (j = i; j < end; j++)
310 ret[j] = 1;
311 }
312 bcm43xx_radio_unlock(bcm);
313 bcm43xx_phy_unlock(bcm, phylock_flags);
314
315 return ret[channel - 1];
316}
317
318/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
319void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val)
320{
321 bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
322 mmiowb();
323 bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val);
324}
325
326/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
327s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset)
328{
329 u16 val;
330
331 bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
332 val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA);
333
334 return (s16)val;
335}
336
337/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
338void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val)
339{
340 u16 i;
341 s16 tmp;
342
343 for (i = 0; i < 64; i++) {
344 tmp = bcm43xx_nrssi_hw_read(bcm, i);
345 tmp -= val;
346 tmp = limit_value(tmp, -32, 31);
347 bcm43xx_nrssi_hw_write(bcm, i, tmp);
348 }
349}
350
351/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
352void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm)
353{
354 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
355 s16 i, delta;
356 s32 tmp;
357
358 delta = 0x1F - radio->nrssi[0];
359 for (i = 0; i < 64; i++) {
360 tmp = (i - delta) * radio->nrssislope;
361 tmp /= 0x10000;
362 tmp += 0x3A;
363 tmp = limit_value(tmp, 0, 0x3F);
364 radio->nrssi_lt[i] = tmp;
365 }
366}
367
368static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
369{
370 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
371 u16 backup[20] = { 0 };
372 s16 v47F;
373 u16 i;
374 u16 saved = 0xFFFF;
375
376 backup[0] = bcm43xx_phy_read(bcm, 0x0001);
377 backup[1] = bcm43xx_phy_read(bcm, 0x0811);
378 backup[2] = bcm43xx_phy_read(bcm, 0x0812);
379 backup[3] = bcm43xx_phy_read(bcm, 0x0814);
380 backup[4] = bcm43xx_phy_read(bcm, 0x0815);
381 backup[5] = bcm43xx_phy_read(bcm, 0x005A);
382 backup[6] = bcm43xx_phy_read(bcm, 0x0059);
383 backup[7] = bcm43xx_phy_read(bcm, 0x0058);
384 backup[8] = bcm43xx_phy_read(bcm, 0x000A);
385 backup[9] = bcm43xx_phy_read(bcm, 0x0003);
386 backup[10] = bcm43xx_radio_read16(bcm, 0x007A);
387 backup[11] = bcm43xx_radio_read16(bcm, 0x0043);
388
389 bcm43xx_phy_write(bcm, 0x0429,
390 bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF);
391 bcm43xx_phy_write(bcm, 0x0001,
392 (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000);
393 bcm43xx_phy_write(bcm, 0x0811,
394 bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
395 bcm43xx_phy_write(bcm, 0x0812,
396 (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004);
397 bcm43xx_phy_write(bcm, 0x0802,
398 bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2));
399 if (phy->rev >= 6) {
400 backup[12] = bcm43xx_phy_read(bcm, 0x002E);
401 backup[13] = bcm43xx_phy_read(bcm, 0x002F);
402 backup[14] = bcm43xx_phy_read(bcm, 0x080F);
403 backup[15] = bcm43xx_phy_read(bcm, 0x0810);
404 backup[16] = bcm43xx_phy_read(bcm, 0x0801);
405 backup[17] = bcm43xx_phy_read(bcm, 0x0060);
406 backup[18] = bcm43xx_phy_read(bcm, 0x0014);
407 backup[19] = bcm43xx_phy_read(bcm, 0x0478);
408
409 bcm43xx_phy_write(bcm, 0x002E, 0);
410 bcm43xx_phy_write(bcm, 0x002F, 0);
411 bcm43xx_phy_write(bcm, 0x080F, 0);
412 bcm43xx_phy_write(bcm, 0x0810, 0);
413 bcm43xx_phy_write(bcm, 0x0478,
414 bcm43xx_phy_read(bcm, 0x0478) | 0x0100);
415 bcm43xx_phy_write(bcm, 0x0801,
416 bcm43xx_phy_read(bcm, 0x0801) | 0x0040);
417 bcm43xx_phy_write(bcm, 0x0060,
418 bcm43xx_phy_read(bcm, 0x0060) | 0x0040);
419 bcm43xx_phy_write(bcm, 0x0014,
420 bcm43xx_phy_read(bcm, 0x0014) | 0x0200);
421 }
422 bcm43xx_radio_write16(bcm, 0x007A,
423 bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
424 bcm43xx_radio_write16(bcm, 0x007A,
425 bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
426 udelay(30);
427
428 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
429 if (v47F >= 0x20)
430 v47F -= 0x40;
431 if (v47F == 31) {
432 for (i = 7; i >= 4; i--) {
433 bcm43xx_radio_write16(bcm, 0x007B, i);
434 udelay(20);
435 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
436 if (v47F >= 0x20)
437 v47F -= 0x40;
438 if (v47F < 31 && saved == 0xFFFF)
439 saved = i;
440 }
441 if (saved == 0xFFFF)
442 saved = 4;
443 } else {
444 bcm43xx_radio_write16(bcm, 0x007A,
445 bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
446 bcm43xx_phy_write(bcm, 0x0814,
447 bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
448 bcm43xx_phy_write(bcm, 0x0815,
449 bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
450 bcm43xx_phy_write(bcm, 0x0811,
451 bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
452 bcm43xx_phy_write(bcm, 0x0812,
453 bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
454 bcm43xx_phy_write(bcm, 0x0811,
455 bcm43xx_phy_read(bcm, 0x0811) | 0x0030);
456 bcm43xx_phy_write(bcm, 0x0812,
457 bcm43xx_phy_read(bcm, 0x0812) | 0x0030);
458 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
459 bcm43xx_phy_write(bcm, 0x0059, 0x0810);
460 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
461 if (phy->rev == 0) {
462 bcm43xx_phy_write(bcm, 0x0003, 0x0122);
463 } else {
464 bcm43xx_phy_write(bcm, 0x000A,
465 bcm43xx_phy_read(bcm, 0x000A)
466 | 0x2000);
467 }
468 bcm43xx_phy_write(bcm, 0x0814,
469 bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
470 bcm43xx_phy_write(bcm, 0x0815,
471 bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
472 bcm43xx_phy_write(bcm, 0x0003,
473 (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F)
474 | 0x0040);
475 bcm43xx_radio_write16(bcm, 0x007A,
476 bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
477 bcm43xx_set_all_gains(bcm, 3, 0, 1);
478 bcm43xx_radio_write16(bcm, 0x0043,
479 (bcm43xx_radio_read16(bcm, 0x0043)
480 & 0x00F0) | 0x000F);
481 udelay(30);
482 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
483 if (v47F >= 0x20)
484 v47F -= 0x40;
485 if (v47F == -32) {
486 for (i = 0; i < 4; i++) {
487 bcm43xx_radio_write16(bcm, 0x007B, i);
488 udelay(20);
489 v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
490 if (v47F >= 0x20)
491 v47F -= 0x40;
492 if (v47F > -31 && saved == 0xFFFF)
493 saved = i;
494 }
495 if (saved == 0xFFFF)
496 saved = 3;
497 } else
498 saved = 0;
499 }
500 bcm43xx_radio_write16(bcm, 0x007B, saved);
501
502 if (phy->rev >= 6) {
503 bcm43xx_phy_write(bcm, 0x002E, backup[12]);
504 bcm43xx_phy_write(bcm, 0x002F, backup[13]);
505 bcm43xx_phy_write(bcm, 0x080F, backup[14]);
506 bcm43xx_phy_write(bcm, 0x0810, backup[15]);
507 }
508 bcm43xx_phy_write(bcm, 0x0814, backup[3]);
509 bcm43xx_phy_write(bcm, 0x0815, backup[4]);
510 bcm43xx_phy_write(bcm, 0x005A, backup[5]);
511 bcm43xx_phy_write(bcm, 0x0059, backup[6]);
512 bcm43xx_phy_write(bcm, 0x0058, backup[7]);
513 bcm43xx_phy_write(bcm, 0x000A, backup[8]);
514 bcm43xx_phy_write(bcm, 0x0003, backup[9]);
515 bcm43xx_radio_write16(bcm, 0x0043, backup[11]);
516 bcm43xx_radio_write16(bcm, 0x007A, backup[10]);
517 bcm43xx_phy_write(bcm, 0x0802,
518 bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2);
519 bcm43xx_phy_write(bcm, 0x0429,
520 bcm43xx_phy_read(bcm, 0x0429) | 0x8000);
521 bcm43xx_set_original_gains(bcm);
522 if (phy->rev >= 6) {
523 bcm43xx_phy_write(bcm, 0x0801, backup[16]);
524 bcm43xx_phy_write(bcm, 0x0060, backup[17]);
525 bcm43xx_phy_write(bcm, 0x0014, backup[18]);
526 bcm43xx_phy_write(bcm, 0x0478, backup[19]);
527 }
528 bcm43xx_phy_write(bcm, 0x0001, backup[0]);
529 bcm43xx_phy_write(bcm, 0x0812, backup[2]);
530 bcm43xx_phy_write(bcm, 0x0811, backup[1]);
531}
532
533void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
534{
535 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
536 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
537 u16 backup[18] = { 0 };
538 u16 tmp;
539 s16 nrssi0, nrssi1;
540
541 switch (phy->type) {
542 case BCM43xx_PHYTYPE_B:
543 backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
544 backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
545 backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
546 backup[3] = bcm43xx_phy_read(bcm, 0x0030);
547 backup[4] = bcm43xx_phy_read(bcm, 0x0026);
548 backup[5] = bcm43xx_phy_read(bcm, 0x0015);
549 backup[6] = bcm43xx_phy_read(bcm, 0x002A);
550 backup[7] = bcm43xx_phy_read(bcm, 0x0020);
551 backup[8] = bcm43xx_phy_read(bcm, 0x005A);
552 backup[9] = bcm43xx_phy_read(bcm, 0x0059);
553 backup[10] = bcm43xx_phy_read(bcm, 0x0058);
554 backup[11] = bcm43xx_read16(bcm, 0x03E2);
555 backup[12] = bcm43xx_read16(bcm, 0x03E6);
556 backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
557
558 tmp = bcm43xx_radio_read16(bcm, 0x007A);
559 tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
560 bcm43xx_radio_write16(bcm, 0x007A, tmp);
561 bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
562 bcm43xx_write16(bcm, 0x03EC, 0x7F7F);
563 bcm43xx_phy_write(bcm, 0x0026, 0x0000);
564 bcm43xx_phy_write(bcm, 0x0015,
565 bcm43xx_phy_read(bcm, 0x0015) | 0x0020);
566 bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
567 bcm43xx_radio_write16(bcm, 0x007A,
568 bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
569
570 nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027);
571 bcm43xx_radio_write16(bcm, 0x007A,
572 bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
573 if (phy->rev >= 2) {
574 bcm43xx_write16(bcm, 0x03E6, 0x0040);
575 } else if (phy->rev == 0) {
576 bcm43xx_write16(bcm, 0x03E6, 0x0122);
577 } else {
578 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
579 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000);
580 }
581 bcm43xx_phy_write(bcm, 0x0020, 0x3F3F);
582 bcm43xx_phy_write(bcm, 0x0015, 0xF330);
583 bcm43xx_radio_write16(bcm, 0x005A, 0x0060);
584 bcm43xx_radio_write16(bcm, 0x0043,
585 bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0);
586 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
587 bcm43xx_phy_write(bcm, 0x0059, 0x0810);
588 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
589 udelay(20);
590
591 nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027);
592 bcm43xx_phy_write(bcm, 0x0030, backup[3]);
593 bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
594 bcm43xx_write16(bcm, 0x03E2, backup[11]);
595 bcm43xx_phy_write(bcm, 0x0026, backup[4]);
596 bcm43xx_phy_write(bcm, 0x0015, backup[5]);
597 bcm43xx_phy_write(bcm, 0x002A, backup[6]);
598 bcm43xx_synth_pu_workaround(bcm, radio->channel);
599 if (phy->rev != 0)
600 bcm43xx_write16(bcm, 0x03F4, backup[13]);
601
602 bcm43xx_phy_write(bcm, 0x0020, backup[7]);
603 bcm43xx_phy_write(bcm, 0x005A, backup[8]);
604 bcm43xx_phy_write(bcm, 0x0059, backup[9]);
605 bcm43xx_phy_write(bcm, 0x0058, backup[10]);
606 bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
607 bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
608
609 if (nrssi0 == nrssi1)
610 radio->nrssislope = 0x00010000;
611 else
612 radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
613
614 if (nrssi0 <= -4) {
615 radio->nrssi[0] = nrssi0;
616 radio->nrssi[1] = nrssi1;
617 }
618 break;
619 case BCM43xx_PHYTYPE_G:
620 if (radio->revision >= 9)
621 return;
622 if (radio->revision == 8)
623 bcm43xx_calc_nrssi_offset(bcm);
624
625 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
626 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
627 bcm43xx_phy_write(bcm, 0x0802,
628 bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
629 backup[7] = bcm43xx_read16(bcm, 0x03E2);
630 bcm43xx_write16(bcm, 0x03E2,
631 bcm43xx_read16(bcm, 0x03E2) | 0x8000);
632 backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
633 backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
634 backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
635 backup[3] = bcm43xx_phy_read(bcm, 0x0015);
636 backup[4] = bcm43xx_phy_read(bcm, 0x005A);
637 backup[5] = bcm43xx_phy_read(bcm, 0x0059);
638 backup[6] = bcm43xx_phy_read(bcm, 0x0058);
639 backup[8] = bcm43xx_read16(bcm, 0x03E6);
640 backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
641 if (phy->rev >= 3) {
642 backup[10] = bcm43xx_phy_read(bcm, 0x002E);
643 backup[11] = bcm43xx_phy_read(bcm, 0x002F);
644 backup[12] = bcm43xx_phy_read(bcm, 0x080F);
645 backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL);
646 backup[14] = bcm43xx_phy_read(bcm, 0x0801);
647 backup[15] = bcm43xx_phy_read(bcm, 0x0060);
648 backup[16] = bcm43xx_phy_read(bcm, 0x0014);
649 backup[17] = bcm43xx_phy_read(bcm, 0x0478);
650 bcm43xx_phy_write(bcm, 0x002E, 0);
651 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0);
652 switch (phy->rev) {
653 case 4: case 6: case 7:
654 bcm43xx_phy_write(bcm, 0x0478,
655 bcm43xx_phy_read(bcm, 0x0478)
656 | 0x0100);
657 bcm43xx_phy_write(bcm, 0x0801,
658 bcm43xx_phy_read(bcm, 0x0801)
659 | 0x0040);
660 break;
661 case 3: case 5:
662 bcm43xx_phy_write(bcm, 0x0801,
663 bcm43xx_phy_read(bcm, 0x0801)
664 & 0xFFBF);
665 break;
666 }
667 bcm43xx_phy_write(bcm, 0x0060,
668 bcm43xx_phy_read(bcm, 0x0060)
669 | 0x0040);
670 bcm43xx_phy_write(bcm, 0x0014,
671 bcm43xx_phy_read(bcm, 0x0014)
672 | 0x0200);
673 }
674 bcm43xx_radio_write16(bcm, 0x007A,
675 bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
676 bcm43xx_set_all_gains(bcm, 0, 8, 0);
677 bcm43xx_radio_write16(bcm, 0x007A,
678 bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7);
679 if (phy->rev >= 2) {
680 bcm43xx_phy_write(bcm, 0x0811,
681 (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030);
682 bcm43xx_phy_write(bcm, 0x0812,
683 (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010);
684 }
685 bcm43xx_radio_write16(bcm, 0x007A,
686 bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
687 udelay(20);
688
689 nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
690 if (nrssi0 >= 0x0020)
691 nrssi0 -= 0x0040;
692
693 bcm43xx_radio_write16(bcm, 0x007A,
694 bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
695 if (phy->rev >= 2) {
696 bcm43xx_phy_write(bcm, 0x0003,
697 (bcm43xx_phy_read(bcm, 0x0003)
698 & 0xFF9F) | 0x0040);
699 }
700
701 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
702 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
703 | 0x2000);
704 bcm43xx_radio_write16(bcm, 0x007A,
705 bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
706 bcm43xx_phy_write(bcm, 0x0015, 0xF330);
707 if (phy->rev >= 2) {
708 bcm43xx_phy_write(bcm, 0x0812,
709 (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020);
710 bcm43xx_phy_write(bcm, 0x0811,
711 (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020);
712 }
713
714 bcm43xx_set_all_gains(bcm, 3, 0, 1);
715 if (radio->revision == 8) {
716 bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
717 } else {
718 tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F;
719 bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060);
720 tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0;
721 bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009);
722 }
723 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
724 bcm43xx_phy_write(bcm, 0x0059, 0x0810);
725 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
726 udelay(20);
727 nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
728 if (nrssi1 >= 0x0020)
729 nrssi1 -= 0x0040;
730 if (nrssi0 == nrssi1)
731 radio->nrssislope = 0x00010000;
732 else
733 radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
734 if (nrssi0 >= -4) {
735 radio->nrssi[0] = nrssi1;
736 radio->nrssi[1] = nrssi0;
737 }
738 if (phy->rev >= 3) {
739 bcm43xx_phy_write(bcm, 0x002E, backup[10]);
740 bcm43xx_phy_write(bcm, 0x002F, backup[11]);
741 bcm43xx_phy_write(bcm, 0x080F, backup[12]);
742 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]);
743 }
744 if (phy->rev >= 2) {
745 bcm43xx_phy_write(bcm, 0x0812,
746 bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF);
747 bcm43xx_phy_write(bcm, 0x0811,
748 bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF);
749 }
750
751 bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
752 bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
753 bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
754 bcm43xx_write16(bcm, 0x03E2, backup[7]);
755 bcm43xx_write16(bcm, 0x03E6, backup[8]);
756 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]);
757 bcm43xx_phy_write(bcm, 0x0015, backup[3]);
758 bcm43xx_phy_write(bcm, 0x005A, backup[4]);
759 bcm43xx_phy_write(bcm, 0x0059, backup[5]);
760 bcm43xx_phy_write(bcm, 0x0058, backup[6]);
761 bcm43xx_synth_pu_workaround(bcm, radio->channel);
762 bcm43xx_phy_write(bcm, 0x0802,
763 bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002));
764 bcm43xx_set_original_gains(bcm);
765 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
766 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
767 if (phy->rev >= 3) {
768 bcm43xx_phy_write(bcm, 0x0801, backup[14]);
769 bcm43xx_phy_write(bcm, 0x0060, backup[15]);
770 bcm43xx_phy_write(bcm, 0x0014, backup[16]);
771 bcm43xx_phy_write(bcm, 0x0478, backup[17]);
772 }
773 bcm43xx_nrssi_mem_update(bcm);
774 bcm43xx_calc_nrssi_threshold(bcm);
775 break;
776 default:
777 assert(0);
778 }
779}
780
781void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm)
782{
783 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
784 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
785 s32 threshold;
786 s32 a, b;
787 s16 tmp16;
788 u16 tmp_u16;
789
790 switch (phy->type) {
791 case BCM43xx_PHYTYPE_B: {
792 if (radio->version != 0x2050)
793 return;
794 if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI))
795 return;
796
797 if (radio->revision >= 6) {
798 threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32;
799 threshold += 20 * (radio->nrssi[0] + 1);
800 threshold /= 40;
801 } else
802 threshold = radio->nrssi[1] - 5;
803
804 threshold = limit_value(threshold, 0, 0x3E);
805 bcm43xx_phy_read(bcm, 0x0020); /* dummy read */
806 bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C);
807
808 if (radio->revision >= 6) {
809 bcm43xx_phy_write(bcm, 0x0087, 0x0E0D);
810 bcm43xx_phy_write(bcm, 0x0086, 0x0C0B);
811 bcm43xx_phy_write(bcm, 0x0085, 0x0A09);
812 bcm43xx_phy_write(bcm, 0x0084, 0x0808);
813 bcm43xx_phy_write(bcm, 0x0083, 0x0808);
814 bcm43xx_phy_write(bcm, 0x0082, 0x0604);
815 bcm43xx_phy_write(bcm, 0x0081, 0x0302);
816 bcm43xx_phy_write(bcm, 0x0080, 0x0100);
817 }
818 break;
819 }
820 case BCM43xx_PHYTYPE_G:
821 if (!phy->connected ||
822 !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
823 tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20);
824 if (tmp16 >= 0x20)
825 tmp16 -= 0x40;
826 if (tmp16 < 3) {
827 bcm43xx_phy_write(bcm, 0x048A,
828 (bcm43xx_phy_read(bcm, 0x048A)
829 & 0xF000) | 0x09EB);
830 } else {
831 bcm43xx_phy_write(bcm, 0x048A,
832 (bcm43xx_phy_read(bcm, 0x048A)
833 & 0xF000) | 0x0AED);
834 }
835 } else {
836 if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) {
837 a = 0xE;
838 b = 0xA;
839 } else if (!radio->aci_wlan_automatic && radio->aci_enable) {
840 a = 0x13;
841 b = 0x12;
842 } else {
843 a = 0xE;
844 b = 0x11;
845 }
846
847 a = a * (radio->nrssi[1] - radio->nrssi[0]);
848 a += (radio->nrssi[0] << 6);
849 if (a < 32)
850 a += 31;
851 else
852 a += 32;
853 a = a >> 6;
854 a = limit_value(a, -31, 31);
855
856 b = b * (radio->nrssi[1] - radio->nrssi[0]);
857 b += (radio->nrssi[0] << 6);
858 if (b < 32)
859 b += 31;
860 else
861 b += 32;
862 b = b >> 6;
863 b = limit_value(b, -31, 31);
864
865 tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000;
866 tmp_u16 |= ((u32)b & 0x0000003F);
867 tmp_u16 |= (((u32)a & 0x0000003F) << 6);
868 bcm43xx_phy_write(bcm, 0x048A, tmp_u16);
869 }
870 break;
871 default:
872 assert(0);
873 }
874}
875
876/* Stack implementation to save/restore values from the
877 * interference mitigation code.
878 * It is save to restore values in random order.
879 */
880static void _stack_save(u32 *_stackptr, size_t *stackidx,
881 u8 id, u16 offset, u16 value)
882{
883 u32 *stackptr = &(_stackptr[*stackidx]);
884
885 assert((offset & 0xF000) == 0x0000);
886 assert((id & 0xF0) == 0x00);
887 *stackptr = offset;
888 *stackptr |= ((u32)id) << 12;
889 *stackptr |= ((u32)value) << 16;
890 (*stackidx)++;
891 assert(*stackidx < BCM43xx_INTERFSTACK_SIZE);
892}
893
894static u16 _stack_restore(u32 *stackptr,
895 u8 id, u16 offset)
896{
897 size_t i;
898
899 assert((offset & 0xF000) == 0x0000);
900 assert((id & 0xF0) == 0x00);
901 for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
902 if ((*stackptr & 0x00000FFF) != offset)
903 continue;
904 if (((*stackptr & 0x0000F000) >> 12) != id)
905 continue;
906 return ((*stackptr & 0xFFFF0000) >> 16);
907 }
908 assert(0);
909
910 return 0;
911}
912
913#define phy_stacksave(offset) \
914 do { \
915 _stack_save(stack, &stackidx, 0x1, (offset), \
916 bcm43xx_phy_read(bcm, (offset))); \
917 } while (0)
918#define phy_stackrestore(offset) \
919 do { \
920 bcm43xx_phy_write(bcm, (offset), \
921 _stack_restore(stack, 0x1, \
922 (offset))); \
923 } while (0)
924#define radio_stacksave(offset) \
925 do { \
926 _stack_save(stack, &stackidx, 0x2, (offset), \
927 bcm43xx_radio_read16(bcm, (offset))); \
928 } while (0)
929#define radio_stackrestore(offset) \
930 do { \
931 bcm43xx_radio_write16(bcm, (offset), \
932 _stack_restore(stack, 0x2, \
933 (offset))); \
934 } while (0)
935#define ilt_stacksave(offset) \
936 do { \
937 _stack_save(stack, &stackidx, 0x3, (offset), \
938 bcm43xx_ilt_read(bcm, (offset))); \
939 } while (0)
940#define ilt_stackrestore(offset) \
941 do { \
942 bcm43xx_ilt_write(bcm, (offset), \
943 _stack_restore(stack, 0x3, \
944 (offset))); \
945 } while (0)
946
947static void
948bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm,
949 int mode)
950{
951 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
952 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
953 u16 tmp, flipped;
954 u32 tmp32;
955 size_t stackidx = 0;
956 u32 *stack = radio->interfstack;
957
958 switch (mode) {
959 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
960 if (phy->rev != 1) {
961 bcm43xx_phy_write(bcm, 0x042B,
962 bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
963 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
964 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000);
965 break;
966 }
967 radio_stacksave(0x0078);
968 tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E);
969 flipped = flip_4bit(tmp);
970 if (flipped < 10 && flipped >= 8)
971 flipped = 7;
972 else if (flipped >= 10)
973 flipped -= 3;
974 flipped = flip_4bit(flipped);
975 flipped = (flipped << 1) | 0x0020;
976 bcm43xx_radio_write16(bcm, 0x0078, flipped);
977
978 bcm43xx_calc_nrssi_threshold(bcm);
979
980 phy_stacksave(0x0406);
981 bcm43xx_phy_write(bcm, 0x0406, 0x7E28);
982
983 bcm43xx_phy_write(bcm, 0x042B,
984 bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
985 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
986 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000);
987
988 phy_stacksave(0x04A0);
989 bcm43xx_phy_write(bcm, 0x04A0,
990 (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008);
991 phy_stacksave(0x04A1);
992 bcm43xx_phy_write(bcm, 0x04A1,
993 (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605);
994 phy_stacksave(0x04A2);
995 bcm43xx_phy_write(bcm, 0x04A2,
996 (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204);
997 phy_stacksave(0x04A8);
998 bcm43xx_phy_write(bcm, 0x04A8,
999 (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803);
1000 phy_stacksave(0x04AB);
1001 bcm43xx_phy_write(bcm, 0x04AB,
1002 (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605);
1003
1004 phy_stacksave(0x04A7);
1005 bcm43xx_phy_write(bcm, 0x04A7, 0x0002);
1006 phy_stacksave(0x04A3);
1007 bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
1008 phy_stacksave(0x04A9);
1009 bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
1010 phy_stacksave(0x0493);
1011 bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
1012 phy_stacksave(0x04AA);
1013 bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
1014 phy_stacksave(0x04AC);
1015 bcm43xx_phy_write(bcm, 0x04AC, 0x32F5);
1016 break;
1017 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
1018 if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800)
1019 break;
1020
1021 radio->aci_enable = 1;
1022
1023 phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD);
1024 phy_stacksave(BCM43xx_PHY_G_CRS);
1025 if (phy->rev < 2) {
1026 phy_stacksave(0x0406);
1027 } else {
1028 phy_stacksave(0x04C0);
1029 phy_stacksave(0x04C1);
1030 }
1031 phy_stacksave(0x0033);
1032 phy_stacksave(0x04A7);
1033 phy_stacksave(0x04A3);
1034 phy_stacksave(0x04A9);
1035 phy_stacksave(0x04AA);
1036 phy_stacksave(0x04AC);
1037 phy_stacksave(0x0493);
1038 phy_stacksave(0x04A1);
1039 phy_stacksave(0x04A0);
1040 phy_stacksave(0x04A2);
1041 phy_stacksave(0x048A);
1042 phy_stacksave(0x04A8);
1043 phy_stacksave(0x04AB);
1044 if (phy->rev == 2) {
1045 phy_stacksave(0x04AD);
1046 phy_stacksave(0x04AE);
1047 } else if (phy->rev >= 3) {
1048 phy_stacksave(0x04AD);
1049 phy_stacksave(0x0415);
1050 phy_stacksave(0x0416);
1051 phy_stacksave(0x0417);
1052 ilt_stacksave(0x1A00 + 0x2);
1053 ilt_stacksave(0x1A00 + 0x3);
1054 }
1055 phy_stacksave(0x042B);
1056 phy_stacksave(0x048C);
1057
1058 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
1059 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)
1060 & ~0x1000);
1061 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1062 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
1063 & 0xFFFC) | 0x0002);
1064
1065 bcm43xx_phy_write(bcm, 0x0033, 0x0800);
1066 bcm43xx_phy_write(bcm, 0x04A3, 0x2027);
1067 bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8);
1068 bcm43xx_phy_write(bcm, 0x0493, 0x287A);
1069 bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8);
1070 bcm43xx_phy_write(bcm, 0x04AC, 0x287A);
1071
1072 bcm43xx_phy_write(bcm, 0x04A0,
1073 (bcm43xx_phy_read(bcm, 0x04A0)
1074 & 0xFFC0) | 0x001A);
1075 bcm43xx_phy_write(bcm, 0x04A7, 0x000D);
1076
1077 if (phy->rev < 2) {
1078 bcm43xx_phy_write(bcm, 0x0406, 0xFF0D);
1079 } else if (phy->rev == 2) {
1080 bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF);
1081 bcm43xx_phy_write(bcm, 0x04C1, 0x00A9);
1082 } else {
1083 bcm43xx_phy_write(bcm, 0x04C0, 0x00C1);
1084 bcm43xx_phy_write(bcm, 0x04C1, 0x0059);
1085 }
1086
1087 bcm43xx_phy_write(bcm, 0x04A1,
1088 (bcm43xx_phy_read(bcm, 0x04A1)
1089 & 0xC0FF) | 0x1800);
1090 bcm43xx_phy_write(bcm, 0x04A1,
1091 (bcm43xx_phy_read(bcm, 0x04A1)
1092 & 0xFFC0) | 0x0015);
1093 bcm43xx_phy_write(bcm, 0x04A8,
1094 (bcm43xx_phy_read(bcm, 0x04A8)
1095 & 0xCFFF) | 0x1000);
1096 bcm43xx_phy_write(bcm, 0x04A8,
1097 (bcm43xx_phy_read(bcm, 0x04A8)
1098 & 0xF0FF) | 0x0A00);
1099 bcm43xx_phy_write(bcm, 0x04AB,
1100 (bcm43xx_phy_read(bcm, 0x04AB)
1101 & 0xCFFF) | 0x1000);
1102 bcm43xx_phy_write(bcm, 0x04AB,
1103 (bcm43xx_phy_read(bcm, 0x04AB)
1104 & 0xF0FF) | 0x0800);
1105 bcm43xx_phy_write(bcm, 0x04AB,
1106 (bcm43xx_phy_read(bcm, 0x04AB)
1107 & 0xFFCF) | 0x0010);
1108 bcm43xx_phy_write(bcm, 0x04AB,
1109 (bcm43xx_phy_read(bcm, 0x04AB)
1110 & 0xFFF0) | 0x0005);
1111 bcm43xx_phy_write(bcm, 0x04A8,
1112 (bcm43xx_phy_read(bcm, 0x04A8)
1113 & 0xFFCF) | 0x0010);
1114 bcm43xx_phy_write(bcm, 0x04A8,
1115 (bcm43xx_phy_read(bcm, 0x04A8)
1116 & 0xFFF0) | 0x0006);
1117 bcm43xx_phy_write(bcm, 0x04A2,
1118 (bcm43xx_phy_read(bcm, 0x04A2)
1119 & 0xF0FF) | 0x0800);
1120 bcm43xx_phy_write(bcm, 0x04A0,
1121 (bcm43xx_phy_read(bcm, 0x04A0)
1122 & 0xF0FF) | 0x0500);
1123 bcm43xx_phy_write(bcm, 0x04A2,
1124 (bcm43xx_phy_read(bcm, 0x04A2)
1125 & 0xFFF0) | 0x000B);
1126
1127 if (phy->rev >= 3) {
1128 bcm43xx_phy_write(bcm, 0x048A,
1129 bcm43xx_phy_read(bcm, 0x048A)
1130 & ~0x8000);
1131 bcm43xx_phy_write(bcm, 0x0415,
1132 (bcm43xx_phy_read(bcm, 0x0415)
1133 & 0x8000) | 0x36D8);
1134 bcm43xx_phy_write(bcm, 0x0416,
1135 (bcm43xx_phy_read(bcm, 0x0416)
1136 & 0x8000) | 0x36D8);
1137 bcm43xx_phy_write(bcm, 0x0417,
1138 (bcm43xx_phy_read(bcm, 0x0417)
1139 & 0xFE00) | 0x016D);
1140 } else {
1141 bcm43xx_phy_write(bcm, 0x048A,
1142 bcm43xx_phy_read(bcm, 0x048A)
1143 | 0x1000);
1144 bcm43xx_phy_write(bcm, 0x048A,
1145 (bcm43xx_phy_read(bcm, 0x048A)
1146 & 0x9FFF) | 0x2000);
1147 tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
1148 BCM43xx_UCODEFLAGS_OFFSET);
1149 if (!(tmp32 & 0x800)) {
1150 tmp32 |= 0x800;
1151 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
1152 BCM43xx_UCODEFLAGS_OFFSET,
1153 tmp32);
1154 }
1155 }
1156 if (phy->rev >= 2) {
1157 bcm43xx_phy_write(bcm, 0x042B,
1158 bcm43xx_phy_read(bcm, 0x042B)
1159 | 0x0800);
1160 }
1161 bcm43xx_phy_write(bcm, 0x048C,
1162 (bcm43xx_phy_read(bcm, 0x048C)
1163 & 0xF0FF) | 0x0200);
1164 if (phy->rev == 2) {
1165 bcm43xx_phy_write(bcm, 0x04AE,
1166 (bcm43xx_phy_read(bcm, 0x04AE)
1167 & 0xFF00) | 0x007F);
1168 bcm43xx_phy_write(bcm, 0x04AD,
1169 (bcm43xx_phy_read(bcm, 0x04AD)
1170 & 0x00FF) | 0x1300);
1171 } else if (phy->rev >= 6) {
1172 bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F);
1173 bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F);
1174 bcm43xx_phy_write(bcm, 0x04AD,
1175 bcm43xx_phy_read(bcm, 0x04AD)
1176 & 0x00FF);
1177 }
1178 bcm43xx_calc_nrssi_slope(bcm);
1179 break;
1180 default:
1181 assert(0);
1182 }
1183}
1184
1185static void
1186bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm,
1187 int mode)
1188{
1189 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1190 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1191 u32 tmp32;
1192 u32 *stack = radio->interfstack;
1193
1194 switch (mode) {
1195 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
1196 if (phy->rev != 1) {
1197 bcm43xx_phy_write(bcm, 0x042B,
1198 bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
1199 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1200 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000);
1201 break;
1202 }
1203 phy_stackrestore(0x0078);
1204 bcm43xx_calc_nrssi_threshold(bcm);
1205 phy_stackrestore(0x0406);
1206 bcm43xx_phy_write(bcm, 0x042B,
1207 bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
1208 if (!bcm->bad_frames_preempt) {
1209 bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
1210 bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)
1211 & ~(1 << 11));
1212 }
1213 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1214 bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000);
1215 phy_stackrestore(0x04A0);
1216 phy_stackrestore(0x04A1);
1217 phy_stackrestore(0x04A2);
1218 phy_stackrestore(0x04A8);
1219 phy_stackrestore(0x04AB);
1220 phy_stackrestore(0x04A7);
1221 phy_stackrestore(0x04A3);
1222 phy_stackrestore(0x04A9);
1223 phy_stackrestore(0x0493);
1224 phy_stackrestore(0x04AA);
1225 phy_stackrestore(0x04AC);
1226 break;
1227 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
1228 if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800))
1229 break;
1230
1231 radio->aci_enable = 0;
1232
1233 phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD);
1234 phy_stackrestore(BCM43xx_PHY_G_CRS);
1235 phy_stackrestore(0x0033);
1236 phy_stackrestore(0x04A3);
1237 phy_stackrestore(0x04A9);
1238 phy_stackrestore(0x0493);
1239 phy_stackrestore(0x04AA);
1240 phy_stackrestore(0x04AC);
1241 phy_stackrestore(0x04A0);
1242 phy_stackrestore(0x04A7);
1243 if (phy->rev >= 2) {
1244 phy_stackrestore(0x04C0);
1245 phy_stackrestore(0x04C1);
1246 } else
1247 phy_stackrestore(0x0406);
1248 phy_stackrestore(0x04A1);
1249 phy_stackrestore(0x04AB);
1250 phy_stackrestore(0x04A8);
1251 if (phy->rev == 2) {
1252 phy_stackrestore(0x04AD);
1253 phy_stackrestore(0x04AE);
1254 } else if (phy->rev >= 3) {
1255 phy_stackrestore(0x04AD);
1256 phy_stackrestore(0x0415);
1257 phy_stackrestore(0x0416);
1258 phy_stackrestore(0x0417);
1259 ilt_stackrestore(0x1A00 + 0x2);
1260 ilt_stackrestore(0x1A00 + 0x3);
1261 }
1262 phy_stackrestore(0x04A2);
1263 phy_stackrestore(0x04A8);
1264 phy_stackrestore(0x042B);
1265 phy_stackrestore(0x048C);
1266 tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
1267 BCM43xx_UCODEFLAGS_OFFSET);
1268 if (tmp32 & 0x800) {
1269 tmp32 &= ~0x800;
1270 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
1271 BCM43xx_UCODEFLAGS_OFFSET,
1272 tmp32);
1273 }
1274 bcm43xx_calc_nrssi_slope(bcm);
1275 break;
1276 default:
1277 assert(0);
1278 }
1279}
1280
1281#undef phy_stacksave
1282#undef phy_stackrestore
1283#undef radio_stacksave
1284#undef radio_stackrestore
1285#undef ilt_stacksave
1286#undef ilt_stackrestore
1287
1288int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm,
1289 int mode)
1290{
1291 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1292 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1293 int currentmode;
1294
1295 if ((phy->type != BCM43xx_PHYTYPE_G) ||
1296 (phy->rev == 0) ||
1297 (!phy->connected))
1298 return -ENODEV;
1299
1300 radio->aci_wlan_automatic = 0;
1301 switch (mode) {
1302 case BCM43xx_RADIO_INTERFMODE_AUTOWLAN:
1303 radio->aci_wlan_automatic = 1;
1304 if (radio->aci_enable)
1305 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
1306 else
1307 mode = BCM43xx_RADIO_INTERFMODE_NONE;
1308 break;
1309 case BCM43xx_RADIO_INTERFMODE_NONE:
1310 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
1311 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
1312 break;
1313 default:
1314 return -EINVAL;
1315 }
1316
1317 currentmode = radio->interfmode;
1318 if (currentmode == mode)
1319 return 0;
1320 if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE)
1321 bcm43xx_radio_interference_mitigation_disable(bcm, currentmode);
1322
1323 if (mode == BCM43xx_RADIO_INTERFMODE_NONE) {
1324 radio->aci_enable = 0;
1325 radio->aci_hw_rssi = 0;
1326 } else
1327 bcm43xx_radio_interference_mitigation_enable(bcm, mode);
1328 radio->interfmode = mode;
1329
1330 return 0;
1331}
1332
1333u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
1334{
1335 u16 reg, index, ret;
1336
1337 reg = bcm43xx_radio_read16(bcm, 0x0060);
1338 index = (reg & 0x001E) >> 1;
1339 ret = rcc_table[index] << 1;
1340 ret |= (reg & 0x0001);
1341 ret |= 0x0020;
1342
1343 return ret;
1344}
1345
1346u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
1347{
1348 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1349 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1350 u16 backup[19] = { 0 };
1351 u16 ret;
1352 u16 i, j;
1353 u32 tmp1 = 0, tmp2 = 0;
1354
1355 backup[0] = bcm43xx_radio_read16(bcm, 0x0043);
1356 backup[14] = bcm43xx_radio_read16(bcm, 0x0051);
1357 backup[15] = bcm43xx_radio_read16(bcm, 0x0052);
1358 backup[1] = bcm43xx_phy_read(bcm, 0x0015);
1359 backup[16] = bcm43xx_phy_read(bcm, 0x005A);
1360 backup[17] = bcm43xx_phy_read(bcm, 0x0059);
1361 backup[18] = bcm43xx_phy_read(bcm, 0x0058);
1362 if (phy->type == BCM43xx_PHYTYPE_B) {
1363 backup[2] = bcm43xx_phy_read(bcm, 0x0030);
1364 backup[3] = bcm43xx_read16(bcm, 0x03EC);
1365 bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
1366 bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
1367 } else {
1368 if (phy->connected) {
1369 backup[4] = bcm43xx_phy_read(bcm, 0x0811);
1370 backup[5] = bcm43xx_phy_read(bcm, 0x0812);
1371 backup[6] = bcm43xx_phy_read(bcm, 0x0814);
1372 backup[7] = bcm43xx_phy_read(bcm, 0x0815);
1373 backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
1374 backup[9] = bcm43xx_phy_read(bcm, 0x0802);
1375 bcm43xx_phy_write(bcm, 0x0814,
1376 (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
1377 bcm43xx_phy_write(bcm, 0x0815,
1378 (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));
1379 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
1380 (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
1381 bcm43xx_phy_write(bcm, 0x0802,
1382 (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
1383 bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
1384 bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
1385 }
1386 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
1387 (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
1388 }
1389 backup[10] = bcm43xx_phy_read(bcm, 0x0035);
1390 bcm43xx_phy_write(bcm, 0x0035,
1391 (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
1392 backup[11] = bcm43xx_read16(bcm, 0x03E6);
1393 backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
1394
1395 // Initialization
1396 if (phy->version == 0) {
1397 bcm43xx_write16(bcm, 0x03E6, 0x0122);
1398 } else {
1399 if (phy->version >= 2)
1400 bcm43xx_write16(bcm, 0x03E6, 0x0040);
1401 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
1402 (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
1403 }
1404
1405 ret = bcm43xx_radio_calibrationvalue(bcm);
1406
1407 if (phy->type == BCM43xx_PHYTYPE_B)
1408 bcm43xx_radio_write16(bcm, 0x0078, 0x0003);
1409
1410 bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
1411 bcm43xx_phy_write(bcm, 0x002B, 0x1403);
1412 if (phy->connected)
1413 bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
1414 bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
1415 bcm43xx_radio_write16(bcm, 0x0051,
1416 (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
1417 bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
1418 bcm43xx_radio_write16(bcm, 0x0043,
1419 bcm43xx_radio_read16(bcm, 0x0043) | 0x0009);
1420 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1421
1422 for (i = 0; i < 16; i++) {
1423 bcm43xx_phy_write(bcm, 0x005A, 0x0480);
1424 bcm43xx_phy_write(bcm, 0x0059, 0xC810);
1425 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
1426 if (phy->connected)
1427 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1428 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1429 udelay(10);
1430 if (phy->connected)
1431 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1432 bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
1433 udelay(10);
1434 if (phy->connected)
1435 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1436 bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
1437 udelay(10);
1438 tmp1 += bcm43xx_phy_read(bcm, 0x002D);
1439 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1440 if (phy->connected)
1441 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1442 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1443 }
1444
1445 tmp1++;
1446 tmp1 >>= 9;
1447 udelay(10);
1448 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1449
1450 for (i = 0; i < 16; i++) {
1451 bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020);
1452 backup[13] = bcm43xx_radio_read16(bcm, 0x0078);
1453 udelay(10);
1454 for (j = 0; j < 16; j++) {
1455 bcm43xx_phy_write(bcm, 0x005A, 0x0D80);
1456 bcm43xx_phy_write(bcm, 0x0059, 0xC810);
1457 bcm43xx_phy_write(bcm, 0x0058, 0x000D);
1458 if (phy->connected)
1459 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1460 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1461 udelay(10);
1462 if (phy->connected)
1463 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1464 bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
1465 udelay(10);
1466 if (phy->connected)
1467 bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
1468 bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
1469 udelay(10);
1470 tmp2 += bcm43xx_phy_read(bcm, 0x002D);
1471 bcm43xx_phy_write(bcm, 0x0058, 0x0000);
1472 if (phy->connected)
1473 bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
1474 bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
1475 }
1476 tmp2++;
1477 tmp2 >>= 8;
1478 if (tmp1 < tmp2)
1479 break;
1480 }
1481
1482 /* Restore the registers */
1483 bcm43xx_phy_write(bcm, 0x0015, backup[1]);
1484 bcm43xx_radio_write16(bcm, 0x0051, backup[14]);
1485 bcm43xx_radio_write16(bcm, 0x0052, backup[15]);
1486 bcm43xx_radio_write16(bcm, 0x0043, backup[0]);
1487 bcm43xx_phy_write(bcm, 0x005A, backup[16]);
1488 bcm43xx_phy_write(bcm, 0x0059, backup[17]);
1489 bcm43xx_phy_write(bcm, 0x0058, backup[18]);
1490 bcm43xx_write16(bcm, 0x03E6, backup[11]);
1491 if (phy->version != 0)
1492 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]);
1493 bcm43xx_phy_write(bcm, 0x0035, backup[10]);
1494 bcm43xx_radio_selectchannel(bcm, radio->channel, 1);
1495 if (phy->type == BCM43xx_PHYTYPE_B) {
1496 bcm43xx_phy_write(bcm, 0x0030, backup[2]);
1497 bcm43xx_write16(bcm, 0x03EC, backup[3]);
1498 } else {
1499 bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
1500 (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
1501 if (phy->connected) {
1502 bcm43xx_phy_write(bcm, 0x0811, backup[4]);
1503 bcm43xx_phy_write(bcm, 0x0812, backup[5]);
1504 bcm43xx_phy_write(bcm, 0x0814, backup[6]);
1505 bcm43xx_phy_write(bcm, 0x0815, backup[7]);
1506 bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
1507 bcm43xx_phy_write(bcm, 0x0802, backup[9]);
1508 }
1509 }
1510 if (i >= 15)
1511 ret = backup[13];
1512
1513 return ret;
1514}
1515
1516void bcm43xx_radio_init2060(struct bcm43xx_private *bcm)
1517{
1518 int err;
1519
1520 bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
1521 bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
1522 bcm43xx_radio_write16(bcm, 0x0009, 0x0040);
1523 bcm43xx_radio_write16(bcm, 0x0005, 0x00AA);
1524 bcm43xx_radio_write16(bcm, 0x0032, 0x008F);
1525 bcm43xx_radio_write16(bcm, 0x0006, 0x008F);
1526 bcm43xx_radio_write16(bcm, 0x0034, 0x008F);
1527 bcm43xx_radio_write16(bcm, 0x002C, 0x0007);
1528 bcm43xx_radio_write16(bcm, 0x0082, 0x0080);
1529 bcm43xx_radio_write16(bcm, 0x0080, 0x0000);
1530 bcm43xx_radio_write16(bcm, 0x003F, 0x00DA);
1531 bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
1532 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010);
1533 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
1534 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
1535 udelay(400);
1536
1537 bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010);
1538 udelay(400);
1539
1540 bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008);
1541 bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010);
1542 bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
1543 bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040);
1544 bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040);
1545 bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008);
1546 bcm43xx_phy_write(bcm, 0x0063, 0xDDC6);
1547 bcm43xx_phy_write(bcm, 0x0069, 0x07BE);
1548 bcm43xx_phy_write(bcm, 0x006A, 0x0000);
1549
1550 err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0);
1551 assert(err == 0);
1552 udelay(1000);
1553}
1554
1555static inline
1556u16 freq_r3A_value(u16 frequency)
1557{
1558 u16 value;
1559
1560 if (frequency < 5091)
1561 value = 0x0040;
1562 else if (frequency < 5321)
1563 value = 0x0000;
1564 else if (frequency < 5806)
1565 value = 0x0080;
1566 else
1567 value = 0x0040;
1568
1569 return value;
1570}
1571
1572void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm)
1573{
1574 static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
1575 static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
1576 u16 tmp = bcm43xx_radio_read16(bcm, 0x001E);
1577 int i, j;
1578
1579 for (i = 0; i < 5; i++) {
1580 for (j = 0; j < 5; j++) {
1581 if (tmp == (data_high[i] << 4 | data_low[j])) {
1582 bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0);
1583 return;
1584 }
1585 }
1586 }
1587}
1588
1589int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
1590 u8 channel,
1591 int synthetic_pu_workaround)
1592{
1593 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1594 u16 r8, tmp;
1595 u16 freq;
1596
1597 if ((radio->manufact == 0x17F) &&
1598 (radio->version == 0x2060) &&
1599 (radio->revision == 1)) {
1600 if (channel > 200)
1601 return -EINVAL;
1602 freq = channel2freq_a(channel);
1603
1604 r8 = bcm43xx_radio_read16(bcm, 0x0008);
1605 bcm43xx_write16(bcm, 0x03F0, freq);
1606 bcm43xx_radio_write16(bcm, 0x0008, r8);
1607
1608 TODO();//TODO: write max channel TX power? to Radio 0x2D
1609 tmp = bcm43xx_radio_read16(bcm, 0x002E);
1610 tmp &= 0x0080;
1611 TODO();//TODO: OR tmp with the Power out estimation for this channel?
1612 bcm43xx_radio_write16(bcm, 0x002E, tmp);
1613
1614 if (freq >= 4920 && freq <= 5500) {
1615 /*
1616 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
1617 * = (freq * 0.025862069
1618 */
1619 r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
1620 }
1621 bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8);
1622 bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8);
1623 bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8);
1624 bcm43xx_radio_write16(bcm, 0x0022,
1625 (bcm43xx_radio_read16(bcm, 0x0022)
1626 & 0x000F) | (r8 << 4));
1627 bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4));
1628 bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4));
1629 bcm43xx_radio_write16(bcm, 0x0008,
1630 (bcm43xx_radio_read16(bcm, 0x0008)
1631 & 0x00F0) | (r8 << 4));
1632 bcm43xx_radio_write16(bcm, 0x0029,
1633 (bcm43xx_radio_read16(bcm, 0x0029)
1634 & 0xFF0F) | 0x00B0);
1635 bcm43xx_radio_write16(bcm, 0x0035, 0x00AA);
1636 bcm43xx_radio_write16(bcm, 0x0036, 0x0085);
1637 bcm43xx_radio_write16(bcm, 0x003A,
1638 (bcm43xx_radio_read16(bcm, 0x003A)
1639 & 0xFF20) | freq_r3A_value(freq));
1640 bcm43xx_radio_write16(bcm, 0x003D,
1641 bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF);
1642 bcm43xx_radio_write16(bcm, 0x0081,
1643 (bcm43xx_radio_read16(bcm, 0x0081)
1644 & 0xFF7F) | 0x0080);
1645 bcm43xx_radio_write16(bcm, 0x0035,
1646 bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF);
1647 bcm43xx_radio_write16(bcm, 0x0035,
1648 (bcm43xx_radio_read16(bcm, 0x0035)
1649 & 0xFFEF) | 0x0010);
1650 bcm43xx_radio_set_tx_iq(bcm);
1651 TODO(); //TODO: TSSI2dbm workaround
1652 bcm43xx_phy_xmitpower(bcm);//FIXME correct?
1653 } else {
1654 if ((channel < 1) || (channel > 14))
1655 return -EINVAL;
1656
1657 if (synthetic_pu_workaround)
1658 bcm43xx_synth_pu_workaround(bcm, channel);
1659
1660 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
1661 channel2freq_bg(channel));
1662
1663 if (channel == 14) {
1664 if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) {
1665 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
1666 BCM43xx_UCODEFLAGS_OFFSET,
1667 bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
1668 BCM43xx_UCODEFLAGS_OFFSET)
1669 & ~(1 << 7));
1670 } else {
1671 bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
1672 BCM43xx_UCODEFLAGS_OFFSET,
1673 bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
1674 BCM43xx_UCODEFLAGS_OFFSET)
1675 | (1 << 7));
1676 }
1677 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
1678 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
1679 | (1 << 11));
1680 } else {
1681 bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
1682 bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
1683 & 0xF7BF);
1684 }
1685 }
1686
1687 radio->channel = channel;
1688 //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
1689 // that 2000 usecs might suffice.
1690 udelay(8000);
1691
1692 return 0;
1693}
1694
1695void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val)
1696{
1697 u16 tmp;
1698
1699 val <<= 8;
1700 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF;
1701 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val);
1702 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF;
1703 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val);
1704 tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF;
1705 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val);
1706}
1707
1708/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
1709static u16 bcm43xx_get_txgain_base_band(u16 txpower)
1710{
1711 u16 ret;
1712
1713 assert(txpower <= 63);
1714
1715 if (txpower >= 54)
1716 ret = 2;
1717 else if (txpower >= 49)
1718 ret = 4;
1719 else if (txpower >= 44)
1720 ret = 5;
1721 else
1722 ret = 6;
1723
1724 return ret;
1725}
1726
1727/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
1728static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower)
1729{
1730 u16 ret;
1731
1732 assert(txpower <= 63);
1733
1734 if (txpower >= 32)
1735 ret = 0;
1736 else if (txpower >= 25)
1737 ret = 1;
1738 else if (txpower >= 20)
1739 ret = 2;
1740 else if (txpower >= 12)
1741 ret = 3;
1742 else
1743 ret = 4;
1744
1745 return ret;
1746}
1747
1748/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
1749static u16 bcm43xx_get_txgain_dac(u16 txpower)
1750{
1751 u16 ret;
1752
1753 assert(txpower <= 63);
1754
1755 if (txpower >= 54)
1756 ret = txpower - 53;
1757 else if (txpower >= 49)
1758 ret = txpower - 42;
1759 else if (txpower >= 44)
1760 ret = txpower - 37;
1761 else if (txpower >= 32)
1762 ret = txpower - 32;
1763 else if (txpower >= 25)
1764 ret = txpower - 20;
1765 else if (txpower >= 20)
1766 ret = txpower - 13;
1767 else if (txpower >= 12)
1768 ret = txpower - 8;
1769 else
1770 ret = txpower;
1771
1772 return ret;
1773}
1774
1775void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower)
1776{
1777 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1778 u16 pamp, base, dac, ilt;
1779
1780 txpower = limit_value(txpower, 0, 63);
1781
1782 pamp = bcm43xx_get_txgain_freq_power_amp(txpower);
1783 pamp <<= 5;
1784 pamp &= 0x00E0;
1785 bcm43xx_phy_write(bcm, 0x0019, pamp);
1786
1787 base = bcm43xx_get_txgain_base_band(txpower);
1788 base &= 0x000F;
1789 bcm43xx_phy_write(bcm, 0x0017, base | 0x0020);
1790
1791 ilt = bcm43xx_ilt_read(bcm, 0x3001);
1792 ilt &= 0x0007;
1793
1794 dac = bcm43xx_get_txgain_dac(txpower);
1795 dac <<= 3;
1796 dac |= ilt;
1797
1798 bcm43xx_ilt_write(bcm, 0x3001, dac);
1799
1800 radio->txpwr_offset = txpower;
1801
1802 TODO();
1803 //TODO: FuncPlaceholder (Adjust BB loft cancel)
1804}
1805
1806void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
1807 u16 baseband_attenuation, u16 radio_attenuation,
1808 u16 txpower)
1809{
1810 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1811 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1812
1813 if (baseband_attenuation == 0xFFFF)
1814 baseband_attenuation = radio->baseband_atten;
1815 if (radio_attenuation == 0xFFFF)
1816 radio_attenuation = radio->radio_atten;
1817 if (txpower == 0xFFFF)
1818 txpower = radio->txctl1;
1819 radio->baseband_atten = baseband_attenuation;
1820 radio->radio_atten = radio_attenuation;
1821 radio->txctl1 = txpower;
1822
1823 assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11);
1824 if (radio->revision < 6)
1825 assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9);
1826 else
1827 assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31);
1828 assert(/*txpower >= 0 &&*/ txpower <= 7);
1829
1830 bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation);
1831 bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation);
1832 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation);
1833 if (radio->version == 0x2050) {
1834 bcm43xx_radio_write16(bcm, 0x0052,
1835 (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070)
1836 | ((txpower << 4) & 0x0070));
1837 }
1838 //FIXME: The spec is very weird and unclear here.
1839 if (phy->type == BCM43xx_PHYTYPE_G)
1840 bcm43xx_phy_lo_adjust(bcm, 0);
1841}
1842
1843u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm)
1844{
1845 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1846
1847 if (radio->version == 0x2050 && radio->revision < 6)
1848 return 0;
1849 return 2;
1850}
1851
1852u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm)
1853{
1854 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1855 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1856 u16 att = 0xFFFF;
1857
1858 if (phy->type == BCM43xx_PHYTYPE_A)
1859 return 0x60;
1860
1861 switch (radio->version) {
1862 case 0x2053:
1863 switch (radio->revision) {
1864 case 1:
1865 att = 6;
1866 break;
1867 }
1868 break;
1869 case 0x2050:
1870 switch (radio->revision) {
1871 case 0:
1872 att = 5;
1873 break;
1874 case 1:
1875 if (phy->type == BCM43xx_PHYTYPE_G) {
1876 if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
1877 bcm->board_type == 0x421 &&
1878 bcm->board_revision >= 30)
1879 att = 3;
1880 else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
1881 bcm->board_type == 0x416)
1882 att = 3;
1883 else
1884 att = 1;
1885 } else {
1886 if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
1887 bcm->board_type == 0x421 &&
1888 bcm->board_revision >= 30)
1889 att = 7;
1890 else
1891 att = 6;
1892 }
1893 break;
1894 case 2:
1895 if (phy->type == BCM43xx_PHYTYPE_G) {
1896 if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
1897 bcm->board_type == 0x421 &&
1898 bcm->board_revision >= 30)
1899 att = 3;
1900 else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
1901 bcm->board_type == 0x416)
1902 att = 5;
1903 else if (bcm->chip_id == 0x4320)
1904 att = 4;
1905 else
1906 att = 3;
1907 } else
1908 att = 6;
1909 break;
1910 case 3:
1911 att = 5;
1912 break;
1913 case 4:
1914 case 5:
1915 att = 1;
1916 break;
1917 case 6:
1918 case 7:
1919 att = 5;
1920 break;
1921 case 8:
1922 att = 0x1A;
1923 break;
1924 case 9:
1925 default:
1926 att = 5;
1927 }
1928 }
1929 if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM &&
1930 bcm->board_type == 0x421) {
1931 if (bcm->board_revision < 0x43)
1932 att = 2;
1933 else if (bcm->board_revision < 0x51)
1934 att = 3;
1935 }
1936 if (att == 0xFFFF)
1937 att = 5;
1938
1939 return att;
1940}
1941
1942u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm)
1943{
1944 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1945
1946 if (radio->version != 0x2050)
1947 return 0;
1948 if (radio->revision == 1)
1949 return 3;
1950 if (radio->revision < 6)
1951 return 2;
1952 if (radio->revision == 8)
1953 return 1;
1954 return 0;
1955}
1956
1957void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
1958{
1959 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1960 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1961 int err;
1962
1963 if (radio->enabled)
1964 return;
1965
1966 switch (phy->type) {
1967 case BCM43xx_PHYTYPE_A:
1968 bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
1969 bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
1970 bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7);
1971 bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7);
1972 bcm43xx_radio_init2060(bcm);
1973 break;
1974 case BCM43xx_PHYTYPE_B:
1975 case BCM43xx_PHYTYPE_G:
1976 bcm43xx_phy_write(bcm, 0x0015, 0x8000);
1977 bcm43xx_phy_write(bcm, 0x0015, 0xCC00);
1978 bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000));
1979 err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1);
1980 assert(err == 0);
1981 break;
1982 default:
1983 assert(0);
1984 }
1985 radio->enabled = 1;
1986 dprintk(KERN_INFO PFX "Radio turned on\n");
1987}
1988
1989void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
1990{
1991 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1992 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
1993
1994 if (phy->type == BCM43xx_PHYTYPE_A) {
1995 bcm43xx_radio_write16(bcm, 0x0004, 0x00FF);
1996 bcm43xx_radio_write16(bcm, 0x0005, 0x00FB);
1997 bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008);
1998 bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008);
1999 }
2000 if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) {
2001 bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C);
2002 bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73);
2003 } else
2004 bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
2005 radio->enabled = 0;
2006 dprintk(KERN_INFO PFX "Radio turned off\n");
2007}
2008
2009void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
2010{
2011 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2012
2013 switch (phy->type) {
2014 case BCM43xx_PHYTYPE_A:
2015 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F);
2016 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F);
2017 break;
2018 case BCM43xx_PHYTYPE_B:
2019 case BCM43xx_PHYTYPE_G:
2020 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F);
2021 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F);
2022 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F);
2023 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F);
2024 break;
2025 }
2026}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
new file mode 100644
index 000000000000..9ed18039fa3e
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -0,0 +1,99 @@
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);
75
76u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm);
77u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm);
78u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm);
79
80void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val);
81
82void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm);
83
84u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel);
85u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm);
86
87int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode);
88
89void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm);
90void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm);
91s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset);
92void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val);
93void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val);
94void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm);
95
96void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm);
97u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm);
98
99#endif /* BCM43xx_RADIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
new file mode 100644
index 000000000000..c44d890b949b
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -0,0 +1,322 @@
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 SYSFS support routines
6
7 Copyright (c) 2006 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_sysfs.h"
27#include "bcm43xx.h"
28#include "bcm43xx_main.h"
29#include "bcm43xx_radio.h"
30
31#include <linux/capability.h>
32
33
34#define GENERIC_FILESIZE 64
35
36
37static int get_integer(const char *buf, size_t count)
38{
39 char tmp[10 + 1] = { 0 };
40 int ret = -EINVAL;
41
42 if (count == 0)
43 goto out;
44 count = min(count, (size_t)10);
45 memcpy(tmp, buf, count);
46 ret = simple_strtol(tmp, NULL, 10);
47out:
48 return ret;
49}
50
51static int get_boolean(const char *buf, size_t count)
52{
53 if (count != 0) {
54 if (buf[0] == '1')
55 return 1;
56 if (buf[0] == '0')
57 return 0;
58 if (count >= 4 && memcmp(buf, "true", 4) == 0)
59 return 1;
60 if (count >= 5 && memcmp(buf, "false", 5) == 0)
61 return 0;
62 if (count >= 3 && memcmp(buf, "yes", 3) == 0)
63 return 1;
64 if (count >= 2 && memcmp(buf, "no", 2) == 0)
65 return 0;
66 if (count >= 2 && memcmp(buf, "on", 2) == 0)
67 return 1;
68 if (count >= 3 && memcmp(buf, "off", 3) == 0)
69 return 0;
70 }
71 return -EINVAL;
72}
73
74static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
75 struct device_attribute *attr,
76 char *buf)
77{
78 struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom);
79 u16 *sprom;
80 unsigned long flags;
81 int i, err;
82
83 if (!capable(CAP_NET_ADMIN))
84 return -EPERM;
85
86 assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE);
87 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
88 GFP_KERNEL);
89 if (!sprom)
90 return -ENOMEM;
91 bcm43xx_lock_mmio(bcm, flags);
92 assert(bcm->initialized);
93 err = bcm43xx_sprom_read(bcm, sprom);
94 if (!err) {
95 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
96 buf[i * 2] = sprom[i] & 0x00FF;
97 buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8;
98 }
99 }
100 bcm43xx_unlock_mmio(bcm, flags);
101 kfree(sprom);
102
103 return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16);
104}
105
106static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
107 struct device_attribute *attr,
108 const char *buf, size_t count)
109{
110 struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom);
111 u16 *sprom;
112 unsigned long flags;
113 int i, err;
114
115 if (!capable(CAP_NET_ADMIN))
116 return -EPERM;
117
118 if (count != BCM43xx_SPROM_SIZE * sizeof(u16))
119 return -EINVAL;
120 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
121 GFP_KERNEL);
122 if (!sprom)
123 return -ENOMEM;
124 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
125 sprom[i] = buf[i * 2] & 0xFF;
126 sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8;
127 }
128 bcm43xx_lock_mmio(bcm, flags);
129 assert(bcm->initialized);
130 err = bcm43xx_sprom_write(bcm, sprom);
131 bcm43xx_unlock_mmio(bcm, flags);
132 kfree(sprom);
133
134 return err ? err : count;
135
136}
137
138static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
139 struct device_attribute *attr,
140 char *buf)
141{
142 struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode);
143 unsigned long flags;
144 int err;
145 ssize_t count = 0;
146
147 if (!capable(CAP_NET_ADMIN))
148 return -EPERM;
149
150 bcm43xx_lock(bcm, flags);
151 assert(bcm->initialized);
152
153 switch (bcm43xx_current_radio(bcm)->interfmode) {
154 case BCM43xx_RADIO_INTERFMODE_NONE:
155 count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n");
156 break;
157 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
158 count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n");
159 break;
160 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
161 count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n");
162 break;
163 default:
164 assert(0);
165 }
166 err = 0;
167
168 bcm43xx_unlock(bcm, flags);
169
170 return err ? err : count;
171
172}
173
174static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
175 struct device_attribute *attr,
176 const char *buf, size_t count)
177{
178 struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode);
179 unsigned long flags;
180 int err;
181 int mode;
182
183 if (!capable(CAP_NET_ADMIN))
184 return -EPERM;
185
186 mode = get_integer(buf, count);
187 switch (mode) {
188 case 0:
189 mode = BCM43xx_RADIO_INTERFMODE_NONE;
190 break;
191 case 1:
192 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
193 break;
194 case 2:
195 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
196 break;
197 case 3:
198 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
199 break;
200 default:
201 return -EINVAL;
202 }
203
204 bcm43xx_lock_mmio(bcm, flags);
205 assert(bcm->initialized);
206
207 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
208 if (err) {
209 printk(KERN_ERR PFX "Interference Mitigation not "
210 "supported by device\n");
211 }
212
213 bcm43xx_unlock_mmio(bcm, flags);
214
215 return err ? err : count;
216}
217
218static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
219 struct device_attribute *attr,
220 char *buf)
221{
222 struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble);
223 unsigned long flags;
224 int err;
225 ssize_t count;
226
227 if (!capable(CAP_NET_ADMIN))
228 return -EPERM;
229
230 bcm43xx_lock(bcm, flags);
231 assert(bcm->initialized);
232
233 if (bcm->short_preamble)
234 count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
235 else
236 count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
237
238 err = 0;
239 bcm43xx_unlock(bcm, flags);
240
241 return err ? err : count;
242}
243
244static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
245 struct device_attribute *attr,
246 const char *buf, size_t count)
247{
248 struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble);
249 unsigned long flags;
250 int err;
251 int value;
252
253 if (!capable(CAP_NET_ADMIN))
254 return -EPERM;
255
256 value = get_boolean(buf, count);
257 if (value < 0)
258 return value;
259 bcm43xx_lock(bcm, flags);
260 assert(bcm->initialized);
261
262 bcm->short_preamble = !!value;
263
264 err = 0;
265 bcm43xx_unlock(bcm, flags);
266
267 return err ? err : count;
268}
269
270int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
271{
272 struct device *dev = &bcm->pci_dev->dev;
273 struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
274 int err;
275
276 assert(bcm->initialized);
277
278 sysfs->attr_sprom.attr.name = "sprom";
279 sysfs->attr_sprom.attr.owner = THIS_MODULE;
280 sysfs->attr_sprom.attr.mode = 0600;
281 sysfs->attr_sprom.show = bcm43xx_attr_sprom_show;
282 sysfs->attr_sprom.store = bcm43xx_attr_sprom_store;
283 err = device_create_file(dev, &sysfs->attr_sprom);
284 if (err)
285 goto out;
286
287 sysfs->attr_interfmode.attr.name = "interference";
288 sysfs->attr_interfmode.attr.owner = THIS_MODULE;
289 sysfs->attr_interfmode.attr.mode = 0600;
290 sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show;
291 sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store;
292 err = device_create_file(dev, &sysfs->attr_interfmode);
293 if (err)
294 goto err_remove_sprom;
295
296 sysfs->attr_preamble.attr.name = "shortpreamble";
297 sysfs->attr_preamble.attr.owner = THIS_MODULE;
298 sysfs->attr_preamble.attr.mode = 0600;
299 sysfs->attr_preamble.show = bcm43xx_attr_preamble_show;
300 sysfs->attr_preamble.store = bcm43xx_attr_preamble_store;
301 err = device_create_file(dev, &sysfs->attr_preamble);
302 if (err)
303 goto err_remove_interfmode;
304
305out:
306 return err;
307err_remove_interfmode:
308 device_remove_file(dev, &sysfs->attr_interfmode);
309err_remove_sprom:
310 device_remove_file(dev, &sysfs->attr_sprom);
311 goto out;
312}
313
314void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
315{
316 struct device *dev = &bcm->pci_dev->dev;
317 struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
318
319 device_remove_file(dev, &sysfs->attr_preamble);
320 device_remove_file(dev, &sysfs->attr_interfmode);
321 device_remove_file(dev, &sysfs->attr_sprom);
322}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h
new file mode 100644
index 000000000000..57f14514e3e0
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h
@@ -0,0 +1,25 @@
1#ifndef BCM43xx_SYSFS_H_
2#define BCM43xx_SYSFS_H_
3
4#include <linux/device.h>
5
6
7struct bcm43xx_sysfs {
8 struct device_attribute attr_sprom;
9 struct device_attribute attr_interfmode;
10 struct device_attribute attr_preamble;
11};
12
13#define devattr_to_bcm(attr, attr_name) ({ \
14 struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \
15 __s = container_of((attr), struct bcm43xx_sysfs, attr_name); \
16 __p = container_of(__s, struct bcm43xx_private, sysfs); \
17 __p; \
18 })
19
20struct bcm43xx_private;
21
22int bcm43xx_sysfs_register(struct bcm43xx_private *bcm);
23void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm);
24
25#endif /* BCM43xx_SYSFS_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..3daee828ef4b
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -0,0 +1,1002 @@
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#include "bcm43xx_phy.h"
44
45
46/* The WIRELESS_EXT version, which is implemented by this driver. */
47#define BCM43xx_WX_VERSION 18
48
49#define MAX_WX_STRING 80
50
51
52static int bcm43xx_wx_get_name(struct net_device *net_dev,
53 struct iw_request_info *info,
54 union iwreq_data *data,
55 char *extra)
56{
57 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
58 unsigned long flags;
59 int i;
60 struct bcm43xx_phyinfo *phy;
61 char suffix[7] = { 0 };
62 int have_a = 0, have_b = 0, have_g = 0;
63
64 bcm43xx_lock(bcm, flags);
65 for (i = 0; i < bcm->nr_80211_available; i++) {
66 phy = &(bcm->core_80211_ext[i].phy);
67 switch (phy->type) {
68 case BCM43xx_PHYTYPE_A:
69 have_a = 1;
70 break;
71 case BCM43xx_PHYTYPE_G:
72 have_g = 1;
73 case BCM43xx_PHYTYPE_B:
74 have_b = 1;
75 break;
76 default:
77 assert(0);
78 }
79 }
80 bcm43xx_unlock(bcm, flags);
81
82 i = 0;
83 if (have_a) {
84 suffix[i++] = 'a';
85 suffix[i++] = '/';
86 }
87 if (have_b) {
88 suffix[i++] = 'b';
89 suffix[i++] = '/';
90 }
91 if (have_g) {
92 suffix[i++] = 'g';
93 suffix[i++] = '/';
94 }
95 if (i != 0)
96 suffix[i - 1] = '\0';
97
98 snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
99
100 return 0;
101}
102
103static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
104 struct iw_request_info *info,
105 union iwreq_data *data,
106 char *extra)
107{
108 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
109 unsigned long flags;
110 u8 channel;
111 int freq;
112 int err = -EINVAL;
113
114 bcm43xx_lock_mmio(bcm, flags);
115 if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
116 channel = data->freq.m;
117 freq = bcm43xx_channel_to_freq(bcm, channel);
118 } else {
119 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
120 freq = data->freq.m;
121 }
122 if (!bcm43xx_is_valid_channel(bcm, channel))
123 goto out_unlock;
124 if (bcm->initialized) {
125 //ieee80211softmac_disassoc(softmac, $REASON);
126 bcm43xx_mac_suspend(bcm);
127 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
128 bcm43xx_mac_enable(bcm);
129 } else {
130 bcm43xx_current_radio(bcm)->initial_channel = channel;
131 err = 0;
132 }
133out_unlock:
134 bcm43xx_unlock_mmio(bcm, flags);
135
136 return err;
137}
138
139static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
140 struct iw_request_info *info,
141 union iwreq_data *data,
142 char *extra)
143{
144 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
145 struct bcm43xx_radioinfo *radio;
146 unsigned long flags;
147 int err = -ENODEV;
148 u16 channel;
149
150 bcm43xx_lock(bcm, flags);
151 radio = bcm43xx_current_radio(bcm);
152 channel = radio->channel;
153 if (channel == 0xFF) {
154 assert(!bcm->initialized);
155 channel = radio->initial_channel;
156 if (channel == 0xFF)
157 goto out_unlock;
158 }
159 assert(channel > 0 && channel <= 1000);
160 data->freq.e = 1;
161 data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
162 data->freq.flags = 1;
163
164 err = 0;
165out_unlock:
166 bcm43xx_unlock(bcm, flags);
167
168 return err;
169}
170
171static int bcm43xx_wx_set_mode(struct net_device *net_dev,
172 struct iw_request_info *info,
173 union iwreq_data *data,
174 char *extra)
175{
176 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
177 unsigned long flags;
178 int mode;
179
180 mode = data->mode;
181 if (mode == IW_MODE_AUTO)
182 mode = BCM43xx_INITIAL_IWMODE;
183
184 bcm43xx_lock_mmio(bcm, flags);
185 if (bcm->ieee->iw_mode != mode)
186 bcm43xx_set_iwmode(bcm, mode);
187 bcm43xx_unlock_mmio(bcm, flags);
188
189 return 0;
190}
191
192static int bcm43xx_wx_get_mode(struct net_device *net_dev,
193 struct iw_request_info *info,
194 union iwreq_data *data,
195 char *extra)
196{
197 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
198 unsigned long flags;
199
200 bcm43xx_lock(bcm, flags);
201 data->mode = bcm->ieee->iw_mode;
202 bcm43xx_unlock(bcm, flags);
203
204 return 0;
205}
206
207static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
208 struct iw_request_info *info,
209 union iwreq_data *data,
210 char *extra)
211{
212 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
213 struct iw_range *range = (struct iw_range *)extra;
214 const struct ieee80211_geo *geo;
215 unsigned long flags;
216 int i, j;
217 struct bcm43xx_phyinfo *phy;
218
219 data->data.length = sizeof(*range);
220 memset(range, 0, sizeof(*range));
221
222 //TODO: What about 802.11b?
223 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
224 range->throughput = 27 * 1000 * 1000;
225
226 range->max_qual.qual = 100;
227 /* TODO: Real max RSSI */
228 range->max_qual.level = 3;
229 range->max_qual.noise = 100;
230 range->max_qual.updated = 7;
231
232 range->avg_qual.qual = 70;
233 range->avg_qual.level = 2;
234 range->avg_qual.noise = 40;
235 range->avg_qual.updated = 7;
236
237 range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
238 range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
239 range->min_frag = MIN_FRAG_THRESHOLD;
240 range->max_frag = MAX_FRAG_THRESHOLD;
241
242 range->encoding_size[0] = 5;
243 range->encoding_size[1] = 13;
244 range->num_encoding_sizes = 2;
245 range->max_encoding_tokens = WEP_KEYS;
246
247 range->we_version_compiled = WIRELESS_EXT;
248 range->we_version_source = BCM43xx_WX_VERSION;
249
250 range->enc_capa = IW_ENC_CAPA_WPA |
251 IW_ENC_CAPA_WPA2 |
252 IW_ENC_CAPA_CIPHER_TKIP |
253 IW_ENC_CAPA_CIPHER_CCMP;
254
255 bcm43xx_lock(bcm, flags);
256 phy = bcm43xx_current_phy(bcm);
257
258 range->num_bitrates = 0;
259 i = 0;
260 if (phy->type == BCM43xx_PHYTYPE_A ||
261 phy->type == BCM43xx_PHYTYPE_G) {
262 range->num_bitrates = 8;
263 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
264 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
265 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
266 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
267 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
268 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
269 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
270 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
271 }
272 if (phy->type == BCM43xx_PHYTYPE_B ||
273 phy->type == BCM43xx_PHYTYPE_G) {
274 range->num_bitrates += 4;
275 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
276 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
277 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
278 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
279 }
280
281 geo = ieee80211_get_geo(bcm->ieee);
282 range->num_channels = geo->a_channels + geo->bg_channels;
283 j = 0;
284 for (i = 0; i < geo->a_channels; i++) {
285 if (j == IW_MAX_FREQUENCIES)
286 break;
287 range->freq[j].i = j + 1;
288 range->freq[j].m = geo->a[i].freq;//FIXME?
289 range->freq[j].e = 1;
290 j++;
291 }
292 for (i = 0; i < geo->bg_channels; i++) {
293 if (j == IW_MAX_FREQUENCIES)
294 break;
295 range->freq[j].i = j + 1;
296 range->freq[j].m = geo->bg[i].freq;//FIXME?
297 range->freq[j].e = 1;
298 j++;
299 }
300 range->num_frequency = j;
301
302 bcm43xx_unlock(bcm, flags);
303
304 return 0;
305}
306
307static int bcm43xx_wx_set_nick(struct net_device *net_dev,
308 struct iw_request_info *info,
309 union iwreq_data *data,
310 char *extra)
311{
312 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
313 unsigned long flags;
314 size_t len;
315
316 bcm43xx_lock(bcm, flags);
317 len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
318 memcpy(bcm->nick, extra, len);
319 bcm->nick[len] = '\0';
320 bcm43xx_unlock(bcm, flags);
321
322 return 0;
323}
324
325static int bcm43xx_wx_get_nick(struct net_device *net_dev,
326 struct iw_request_info *info,
327 union iwreq_data *data,
328 char *extra)
329{
330 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
331 unsigned long flags;
332 size_t len;
333
334 bcm43xx_lock(bcm, flags);
335 len = strlen(bcm->nick) + 1;
336 memcpy(extra, bcm->nick, len);
337 data->data.length = (__u16)len;
338 data->data.flags = 1;
339 bcm43xx_unlock(bcm, flags);
340
341 return 0;
342}
343
344static int bcm43xx_wx_set_rts(struct net_device *net_dev,
345 struct iw_request_info *info,
346 union iwreq_data *data,
347 char *extra)
348{
349 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
350 unsigned long flags;
351 int err = -EINVAL;
352
353 bcm43xx_lock(bcm, flags);
354 if (data->rts.disabled) {
355 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
356 err = 0;
357 } else {
358 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
359 data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
360 bcm->rts_threshold = data->rts.value;
361 err = 0;
362 }
363 }
364 bcm43xx_unlock(bcm, flags);
365
366 return err;
367}
368
369static int bcm43xx_wx_get_rts(struct net_device *net_dev,
370 struct iw_request_info *info,
371 union iwreq_data *data,
372 char *extra)
373{
374 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
375 unsigned long flags;
376
377 bcm43xx_lock(bcm, flags);
378 data->rts.value = bcm->rts_threshold;
379 data->rts.fixed = 0;
380 data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
381 bcm43xx_unlock(bcm, flags);
382
383 return 0;
384}
385
386static int bcm43xx_wx_set_frag(struct net_device *net_dev,
387 struct iw_request_info *info,
388 union iwreq_data *data,
389 char *extra)
390{
391 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
392 unsigned long flags;
393 int err = -EINVAL;
394
395 bcm43xx_lock(bcm, flags);
396 if (data->frag.disabled) {
397 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
398 err = 0;
399 } else {
400 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
401 data->frag.value <= MAX_FRAG_THRESHOLD) {
402 bcm->ieee->fts = data->frag.value & ~0x1;
403 err = 0;
404 }
405 }
406 bcm43xx_unlock(bcm, flags);
407
408 return err;
409}
410
411static int bcm43xx_wx_get_frag(struct net_device *net_dev,
412 struct iw_request_info *info,
413 union iwreq_data *data,
414 char *extra)
415{
416 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
417 unsigned long flags;
418
419 bcm43xx_lock(bcm, flags);
420 data->frag.value = bcm->ieee->fts;
421 data->frag.fixed = 0;
422 data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
423 bcm43xx_unlock(bcm, flags);
424
425 return 0;
426}
427
428static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
429 struct iw_request_info *info,
430 union iwreq_data *data,
431 char *extra)
432{
433 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
434 struct bcm43xx_radioinfo *radio;
435 struct bcm43xx_phyinfo *phy;
436 unsigned long flags;
437 int err = -ENODEV;
438 u16 maxpower;
439
440 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
441 printk(PFX KERN_ERR "TX power not in dBm.\n");
442 return -EOPNOTSUPP;
443 }
444
445 bcm43xx_lock_mmio(bcm, flags);
446 if (!bcm->initialized)
447 goto out_unlock;
448 radio = bcm43xx_current_radio(bcm);
449 phy = bcm43xx_current_phy(bcm);
450 if (data->txpower.disabled != (!(radio->enabled))) {
451 if (data->txpower.disabled)
452 bcm43xx_radio_turn_off(bcm);
453 else
454 bcm43xx_radio_turn_on(bcm);
455 }
456 if (data->txpower.value > 0) {
457 /* desired and maxpower dBm values are in Q5.2 */
458 if (phy->type == BCM43xx_PHYTYPE_A)
459 maxpower = bcm->sprom.maxpower_aphy;
460 else
461 maxpower = bcm->sprom.maxpower_bgphy;
462 radio->txpower_desired = limit_value(data->txpower.value << 2,
463 0, maxpower);
464 bcm43xx_phy_xmitpower(bcm);
465 }
466 err = 0;
467
468out_unlock:
469 bcm43xx_unlock_mmio(bcm, flags);
470
471 return err;
472}
473
474static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
475 struct iw_request_info *info,
476 union iwreq_data *data,
477 char *extra)
478{
479 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
480 struct bcm43xx_radioinfo *radio;
481 unsigned long flags;
482 int err = -ENODEV;
483
484 bcm43xx_lock(bcm, flags);
485 if (!bcm->initialized)
486 goto out_unlock;
487 radio = bcm43xx_current_radio(bcm);
488 /* desired dBm value is in Q5.2 */
489 data->txpower.value = radio->txpower_desired >> 2;
490 data->txpower.fixed = 1;
491 data->txpower.flags = IW_TXPOW_DBM;
492 data->txpower.disabled = !(radio->enabled);
493
494 err = 0;
495out_unlock:
496 bcm43xx_unlock(bcm, flags);
497
498 return err;
499}
500
501static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
502 struct iw_request_info *info,
503 union iwreq_data *data,
504 char *extra)
505{
506 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
507 int err;
508
509 err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
510
511 return err;
512}
513
514static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
515 struct iw_request_info *info,
516 union iwreq_data *data,
517 char *extra)
518{
519 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
520 int err;
521
522 err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
523
524 return err;
525}
526
527static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
528 struct iw_request_info *info,
529 union iwreq_data *data,
530 char *extra)
531{
532 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
533 int err;
534
535 err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
536
537 return err;
538}
539
540static int bcm43xx_wx_get_encodingext(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 err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
549
550 return err;
551}
552
553static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
554 struct iw_request_info *info,
555 union iwreq_data *data,
556 char *extra)
557{
558 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
559 unsigned long flags;
560 int mode, err = 0;
561
562 mode = *((int *)extra);
563 switch (mode) {
564 case 0:
565 mode = BCM43xx_RADIO_INTERFMODE_NONE;
566 break;
567 case 1:
568 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
569 break;
570 case 2:
571 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
572 break;
573 case 3:
574 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
575 break;
576 default:
577 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
578 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
579 "3 => Auto-WLAN\n");
580 return -EINVAL;
581 }
582
583 bcm43xx_lock_mmio(bcm, flags);
584 if (bcm->initialized) {
585 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
586 if (err) {
587 printk(KERN_ERR PFX "Interference Mitigation not "
588 "supported by device\n");
589 }
590 } else {
591 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
592 printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
593 "not supported while the interface is down.\n");
594 err = -ENODEV;
595 } else
596 bcm43xx_current_radio(bcm)->interfmode = mode;
597 }
598 bcm43xx_unlock_mmio(bcm, flags);
599
600 return err;
601}
602
603static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
604 struct iw_request_info *info,
605 union iwreq_data *data,
606 char *extra)
607{
608 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
609 unsigned long flags;
610 int mode;
611
612 bcm43xx_lock(bcm, flags);
613 mode = bcm43xx_current_radio(bcm)->interfmode;
614 bcm43xx_unlock(bcm, flags);
615
616 switch (mode) {
617 case BCM43xx_RADIO_INTERFMODE_NONE:
618 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
619 break;
620 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
621 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
622 break;
623 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
624 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
625 break;
626 default:
627 assert(0);
628 }
629 data->data.length = strlen(extra) + 1;
630
631 return 0;
632}
633
634static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
635 struct iw_request_info *info,
636 union iwreq_data *data,
637 char *extra)
638{
639 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
640 unsigned long flags;
641 int on;
642
643 on = *((int *)extra);
644 bcm43xx_lock(bcm, flags);
645 bcm->short_preamble = !!on;
646 bcm43xx_unlock(bcm, flags);
647
648 return 0;
649}
650
651static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
652 struct iw_request_info *info,
653 union iwreq_data *data,
654 char *extra)
655{
656 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
657 unsigned long flags;
658 int on;
659
660 bcm43xx_lock(bcm, flags);
661 on = bcm->short_preamble;
662 bcm43xx_unlock(bcm, flags);
663
664 if (on)
665 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
666 else
667 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
668 data->data.length = strlen(extra) + 1;
669
670 return 0;
671}
672
673static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
674 struct iw_request_info *info,
675 union iwreq_data *data,
676 char *extra)
677{
678 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
679 unsigned long flags;
680 int on;
681
682 on = *((int *)extra);
683
684 bcm43xx_lock(bcm, flags);
685 bcm->ieee->host_encrypt = !!on;
686 bcm->ieee->host_decrypt = !!on;
687 bcm->ieee->host_build_iv = !on;
688 bcm43xx_unlock(bcm, flags);
689
690 return 0;
691}
692
693static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
694 struct iw_request_info *info,
695 union iwreq_data *data,
696 char *extra)
697{
698 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
699 unsigned long flags;
700 int on;
701
702 bcm43xx_lock(bcm, flags);
703 on = bcm->ieee->host_encrypt;
704 bcm43xx_unlock(bcm, flags);
705
706 if (on)
707 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
708 else
709 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
710 data->data.length = strlen(extra + 1);
711
712 return 0;
713}
714
715/* Enough buffer to hold a hexdump of the sprom data. */
716#define SPROM_BUFFERSIZE 512
717
718static int sprom2hex(const u16 *sprom, char *dump)
719{
720 int i, pos = 0;
721
722 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
723 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
724 "%04X", swab16(sprom[i]) & 0xFFFF);
725 }
726
727 return pos + 1;
728}
729
730static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
731{
732 char tmp[5] = { 0 };
733 int cnt = 0;
734 unsigned long parsed;
735
736 if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
737 return -EINVAL;
738 while (cnt < BCM43xx_SPROM_SIZE) {
739 memcpy(tmp, dump, 4);
740 dump += 4;
741 parsed = simple_strtoul(tmp, NULL, 16);
742 sprom[cnt++] = swab16((u16)parsed);
743 }
744
745 return 0;
746}
747
748static int bcm43xx_wx_sprom_read(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 int err = -EPERM;
755 u16 *sprom;
756 unsigned long flags;
757
758 if (!capable(CAP_SYS_RAWIO))
759 goto out;
760
761 err = -ENOMEM;
762 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
763 GFP_KERNEL);
764 if (!sprom)
765 goto out;
766
767 bcm43xx_lock_mmio(bcm, flags);
768 err = -ENODEV;
769 if (bcm->initialized)
770 err = bcm43xx_sprom_read(bcm, sprom);
771 bcm43xx_unlock_mmio(bcm, flags);
772 if (!err)
773 data->data.length = sprom2hex(sprom, extra);
774 kfree(sprom);
775out:
776 return err;
777}
778
779static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
780 struct iw_request_info *info,
781 union iwreq_data *data,
782 char *extra)
783{
784 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
785 int err = -EPERM;
786 u16 *sprom;
787 unsigned long flags;
788 char *input;
789 unsigned int len;
790
791 if (!capable(CAP_SYS_RAWIO))
792 goto out;
793
794 err = -ENOMEM;
795 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
796 GFP_KERNEL);
797 if (!sprom)
798 goto out;
799
800 len = data->data.length;
801 extra[len - 1] = '\0';
802 input = strchr(extra, ':');
803 if (input) {
804 input++;
805 len -= input - extra;
806 } else
807 input = extra;
808 err = hex2sprom(sprom, input, len);
809 if (err)
810 goto out_kfree;
811
812 bcm43xx_lock_mmio(bcm, flags);
813 err = -ENODEV;
814 if (bcm->initialized)
815 err = bcm43xx_sprom_write(bcm, sprom);
816 bcm43xx_unlock_mmio(bcm, flags);
817out_kfree:
818 kfree(sprom);
819out:
820 return err;
821}
822
823/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
824
825static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
826{
827 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
828 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
829 struct iw_statistics *wstats;
830
831 wstats = &bcm->stats.wstats;
832 if (!mac->associated) {
833 wstats->miss.beacon = 0;
834// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
835 wstats->discard.retries = 0;
836// bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
837 wstats->discard.nwid = 0;
838// bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
839 wstats->discard.code = 0;
840// bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here
841 wstats->discard.fragment = 0;
842 wstats->discard.misc = 0;
843 wstats->qual.qual = 0;
844 wstats->qual.level = 0;
845 wstats->qual.noise = 0;
846 wstats->qual.updated = 7;
847 wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
848 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
849 return wstats;
850 }
851 /* fill in the real statistics when iface associated */
852 wstats->qual.qual = 100; // TODO: get the real signal quality
853 wstats->qual.level = 3 - bcm->stats.link_quality;
854 wstats->qual.noise = bcm->stats.noise;
855 wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
856 IW_QUAL_NOISE_UPDATED;
857 wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
858 wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
859 wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
860 wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
861 wstats->discard.misc = 0; // FIXME
862 wstats->miss.beacon = 0; // FIXME
863 return wstats;
864}
865
866
867#ifdef WX
868# undef WX
869#endif
870#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
871static const iw_handler bcm43xx_wx_handlers[] = {
872 /* Wireless Identification */
873 WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
874 /* Basic operations */
875 WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
876 WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
877 WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
878 WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
879 /* Informative stuff */
880 WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
881 /* Access Point manipulation */
882 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
883 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
884 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
885 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
886 /* 802.11 specific support */
887 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
888 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
889 WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
890 WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
891 /* Other parameters */
892 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
893 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
894 WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
895 WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
896 WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
897 WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
898 WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
899 WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
900//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
901//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
902 /* Encoding */
903 WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
904 WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
905 WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
906 WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
907 /* Power saving */
908//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
909//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
910 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
911 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
912 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
913 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
914};
915#undef WX
916
917static const iw_handler bcm43xx_priv_wx_handlers[] = {
918 /* Set Interference Mitigation Mode. */
919 bcm43xx_wx_set_interfmode,
920 /* Get Interference Mitigation Mode. */
921 bcm43xx_wx_get_interfmode,
922 /* Enable/Disable Short Preamble mode. */
923 bcm43xx_wx_set_shortpreamble,
924 /* Get Short Preamble mode. */
925 bcm43xx_wx_get_shortpreamble,
926 /* Enable/Disable Software Encryption mode */
927 bcm43xx_wx_set_swencryption,
928 /* Get Software Encryption mode */
929 bcm43xx_wx_get_swencryption,
930 /* Write SRPROM data. */
931 bcm43xx_wx_sprom_write,
932 /* Read SPROM data. */
933 bcm43xx_wx_sprom_read,
934};
935
936#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
937#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
938#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
939#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
940#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
941#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
942#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
943#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
944
945#define PRIV_WX_DUMMY(ioctl) \
946 { \
947 .cmd = (ioctl), \
948 .name = "__unused" \
949 }
950
951static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
952 {
953 .cmd = PRIV_WX_SET_INTERFMODE,
954 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
955 .name = "set_interfmode",
956 },
957 {
958 .cmd = PRIV_WX_GET_INTERFMODE,
959 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
960 .name = "get_interfmode",
961 },
962 {
963 .cmd = PRIV_WX_SET_SHORTPREAMBLE,
964 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
965 .name = "set_shortpreambl",
966 },
967 {
968 .cmd = PRIV_WX_GET_SHORTPREAMBLE,
969 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
970 .name = "get_shortpreambl",
971 },
972 {
973 .cmd = PRIV_WX_SET_SWENCRYPTION,
974 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
975 .name = "set_swencryption",
976 },
977 {
978 .cmd = PRIV_WX_GET_SWENCRYPTION,
979 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
980 .name = "get_swencryption",
981 },
982 {
983 .cmd = PRIV_WX_SPROM_WRITE,
984 .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
985 .name = "write_sprom",
986 },
987 {
988 .cmd = PRIV_WX_SPROM_READ,
989 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
990 .name = "read_sprom",
991 },
992};
993
994const struct iw_handler_def bcm43xx_wx_handlers_def = {
995 .standard = bcm43xx_wx_handlers,
996 .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
997 .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
998 .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
999 .private = bcm43xx_priv_wx_handlers,
1000 .private_args = bcm43xx_priv_wx_args,
1001 .get_wireless_stats = bcm43xx_get_wireless_stats,
1002};
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_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
new file mode 100644
index 000000000000..d8ece28c079f
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -0,0 +1,582 @@
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 Transmission (TX/RX) related functions.
6
7 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
8 Stefano Brivio <st3@riseup.net>
9 Michael Buesch <mbuesch@freenet.de>
10 Danny van Dyk <kugelfang@gentoo.org>
11 Andreas Jaggi <andreas.jaggi@waterwave.ch>
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_xmit.h"
31
32#include <linux/etherdevice.h>
33
34
35/* Extract the bitrate out of a CCK PLCP header. */
36static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp)
37{
38 switch (plcp->raw[0]) {
39 case 0x0A:
40 return IEEE80211_CCK_RATE_1MB;
41 case 0x14:
42 return IEEE80211_CCK_RATE_2MB;
43 case 0x37:
44 return IEEE80211_CCK_RATE_5MB;
45 case 0x6E:
46 return IEEE80211_CCK_RATE_11MB;
47 }
48 assert(0);
49 return 0;
50}
51
52/* Extract the bitrate out of an OFDM PLCP header. */
53static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp)
54{
55 switch (plcp->raw[0] & 0xF) {
56 case 0xB:
57 return IEEE80211_OFDM_RATE_6MB;
58 case 0xF:
59 return IEEE80211_OFDM_RATE_9MB;
60 case 0xA:
61 return IEEE80211_OFDM_RATE_12MB;
62 case 0xE:
63 return IEEE80211_OFDM_RATE_18MB;
64 case 0x9:
65 return IEEE80211_OFDM_RATE_24MB;
66 case 0xD:
67 return IEEE80211_OFDM_RATE_36MB;
68 case 0x8:
69 return IEEE80211_OFDM_RATE_48MB;
70 case 0xC:
71 return IEEE80211_OFDM_RATE_54MB;
72 }
73 assert(0);
74 return 0;
75}
76
77u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
78{
79 switch (bitrate) {
80 case IEEE80211_CCK_RATE_1MB:
81 return 0x0A;
82 case IEEE80211_CCK_RATE_2MB:
83 return 0x14;
84 case IEEE80211_CCK_RATE_5MB:
85 return 0x37;
86 case IEEE80211_CCK_RATE_11MB:
87 return 0x6E;
88 }
89 assert(0);
90 return 0;
91}
92
93u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
94{
95 switch (bitrate) {
96 case IEEE80211_OFDM_RATE_6MB:
97 return 0xB;
98 case IEEE80211_OFDM_RATE_9MB:
99 return 0xF;
100 case IEEE80211_OFDM_RATE_12MB:
101 return 0xA;
102 case IEEE80211_OFDM_RATE_18MB:
103 return 0xE;
104 case IEEE80211_OFDM_RATE_24MB:
105 return 0x9;
106 case IEEE80211_OFDM_RATE_36MB:
107 return 0xD;
108 case IEEE80211_OFDM_RATE_48MB:
109 return 0x8;
110 case IEEE80211_OFDM_RATE_54MB:
111 return 0xC;
112 }
113 assert(0);
114 return 0;
115}
116
117static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
118 const u16 octets, const u8 bitrate,
119 const int ofdm_modulation)
120{
121 __le32 *data = &(plcp->data);
122 __u8 *raw = plcp->raw;
123
124 if (ofdm_modulation) {
125 *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
126 assert(!(octets & 0xF000));
127 *data |= (octets << 5);
128 *data = cpu_to_le32(*data);
129 } else {
130 u32 plen;
131
132 plen = octets * 16 / bitrate;
133 if ((octets * 16 % bitrate) > 0) {
134 plen++;
135 if ((bitrate == IEEE80211_CCK_RATE_11MB)
136 && ((octets * 8 % 11) < 4)) {
137 raw[1] = 0x84;
138 } else
139 raw[1] = 0x04;
140 } else
141 raw[1] = 0x04;
142 *data |= cpu_to_le32(plen << 16);
143 raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
144 }
145}
146
147static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
148{
149 switch (bitrate) {
150 case IEEE80211_CCK_RATE_1MB:
151 return IEEE80211_CCK_RATE_1MB;
152 case IEEE80211_CCK_RATE_2MB:
153 return IEEE80211_CCK_RATE_1MB;
154 case IEEE80211_CCK_RATE_5MB:
155 return IEEE80211_CCK_RATE_2MB;
156 case IEEE80211_CCK_RATE_11MB:
157 return IEEE80211_CCK_RATE_5MB;
158 case IEEE80211_OFDM_RATE_6MB:
159 return IEEE80211_CCK_RATE_5MB;
160 case IEEE80211_OFDM_RATE_9MB:
161 return IEEE80211_OFDM_RATE_6MB;
162 case IEEE80211_OFDM_RATE_12MB:
163 return IEEE80211_OFDM_RATE_9MB;
164 case IEEE80211_OFDM_RATE_18MB:
165 return IEEE80211_OFDM_RATE_12MB;
166 case IEEE80211_OFDM_RATE_24MB:
167 return IEEE80211_OFDM_RATE_18MB;
168 case IEEE80211_OFDM_RATE_36MB:
169 return IEEE80211_OFDM_RATE_24MB;
170 case IEEE80211_OFDM_RATE_48MB:
171 return IEEE80211_OFDM_RATE_36MB;
172 case IEEE80211_OFDM_RATE_54MB:
173 return IEEE80211_OFDM_RATE_48MB;
174 }
175 assert(0);
176 return 0;
177}
178
179static
180__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header,
181 u8 bitrate)
182{
183 const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl);
184 __le16 duration_id = wireless_header->duration_id;
185
186 switch (WLAN_FC_GET_TYPE(frame_ctl)) {
187 case IEEE80211_FTYPE_DATA:
188 case IEEE80211_FTYPE_MGMT:
189 //TODO: Steal the code from ieee80211, once it is completed there.
190 break;
191 case IEEE80211_FTYPE_CTL:
192 /* Use the original duration/id. */
193 break;
194 default:
195 assert(0);
196 }
197
198 return duration_id;
199}
200
201static inline
202u16 ceiling_div(u16 dividend, u16 divisor)
203{
204 return ((dividend + divisor - 1) / divisor);
205}
206
207static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy,
208 struct bcm43xx_txhdr *txhdr,
209 u16 *flags,
210 u8 bitrate,
211 const struct ieee80211_hdr_4addr *wlhdr)
212{
213 u16 fctl;
214 u16 dur;
215 u8 fallback_bitrate;
216 int ofdm_modulation;
217 int fallback_ofdm_modulation;
218// u8 *sa, *da;
219 u16 flen;
220
221//FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr);
222//FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr);
223 fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
224 ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
225 fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
226
227 flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN,
228 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
229 flen, bitrate,
230 !ieee80211_is_cck_rate(bitrate));
231 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
232 flen, fallback_bitrate,
233 !ieee80211_is_cck_rate(fallback_bitrate));
234 fctl = IEEE80211_FTYPE_CTL;
235 fctl |= IEEE80211_STYPE_RTS;
236 dur = le16_to_cpu(wlhdr->duration_id);
237/*FIXME: should we test for dur==0 here and let it unmodified in this case?
238 * The following assert checks for this case...
239 */
240assert(dur);
241/*FIXME: The duration calculation is not really correct.
242 * I am not 100% sure which bitrate to use. We use the RTS rate here,
243 * but this is likely to be wrong.
244 */
245 if (phy->type == BCM43xx_PHYTYPE_A) {
246 /* Three times SIFS */
247 dur += 16 * 3;
248 /* Add ACK duration. */
249 dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
250 bitrate * 4);
251 /* Add CTS duration. */
252 dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
253 bitrate * 4);
254 } else {
255 /* Three times SIFS */
256 dur += 10 * 3;
257 /* Add ACK duration. */
258 dur += ceiling_div(8 * (14 /*bytes*/) * 10,
259 bitrate);
260 /* Add CTS duration. */
261 dur += ceiling_div(8 * (14 /*bytes*/) * 10,
262 bitrate);
263 }
264
265 txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
266 txhdr->rts_cts_dur = cpu_to_le16(dur);
267//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3));
268//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da));
269 memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME!
270// memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
271
272 *flags |= BCM43xx_TXHDRFLAG_RTSCTS;
273 *flags |= BCM43xx_TXHDRFLAG_RTS;
274 if (ofdm_modulation)
275 *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
276 if (fallback_ofdm_modulation)
277 *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
278}
279
280void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
281 struct bcm43xx_txhdr *txhdr,
282 const unsigned char *fragment_data,
283 const unsigned int fragment_len,
284 const int is_first_fragment,
285 const u16 cookie)
286{
287 const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
288 const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data;
289 const struct ieee80211_security *secinfo = &bcm->ieee->sec;
290 u8 bitrate;
291 u8 fallback_bitrate;
292 int ofdm_modulation;
293 int fallback_ofdm_modulation;
294 u16 plcp_fragment_len = fragment_len;
295 u16 flags = 0;
296 u16 control = 0;
297 u16 wsec_rate = 0;
298 u16 encrypt_frame;
299
300 /* Now construct the TX header. */
301 memset(txhdr, 0, sizeof(*txhdr));
302
303 bitrate = bcm->softmac->txrates.default_rate;
304 ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
305 fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
306 fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
307
308 /* Set Frame Control from 80211 header. */
309 txhdr->frame_control = wireless_header->frame_ctl;
310 /* Copy address1 from 80211 header. */
311 memcpy(txhdr->mac1, wireless_header->addr1, 6);
312 /* Set the fallback duration ID. */
313 txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header,
314 fallback_bitrate);
315 /* Set the cookie (used as driver internal ID for the frame) */
316 txhdr->cookie = cpu_to_le16(cookie);
317
318 /* Hardware appends FCS. */
319 plcp_fragment_len += IEEE80211_FCS_LEN;
320
321 /* Hardware encryption. */
322 encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
323 if (encrypt_frame && !bcm->ieee->host_encrypt) {
324 const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
325 memcpy(txhdr->wep_iv, hdr->payload, 4);
326 /* Hardware appends ICV. */
327 plcp_fragment_len += 4;
328
329 wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
330 & BCM43xx_TXHDR_WSEC_ALGO_MASK;
331 wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
332 & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
333 }
334
335 /* Generate the PLCP header and the fallback PLCP header. */
336 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
337 plcp_fragment_len,
338 bitrate, ofdm_modulation);
339 bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
340 fallback_bitrate, fallback_ofdm_modulation);
341
342 /* Set the CONTROL field */
343 if (ofdm_modulation)
344 control |= BCM43xx_TXHDRCTL_OFDM;
345 if (bcm->short_preamble) //FIXME: could be the other way around, please test
346 control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
347 control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
348 & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
349
350 /* Set the FLAGS field */
351 if (!is_multicast_ether_addr(wireless_header->addr1) &&
352 !is_broadcast_ether_addr(wireless_header->addr1))
353 flags |= BCM43xx_TXHDRFLAG_EXPECTACK;
354 if (1 /* FIXME: PS poll?? */)
355 flags |= 0x10; // FIXME: unknown meaning.
356 if (fallback_ofdm_modulation)
357 flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
358 if (is_first_fragment)
359 flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
360
361 /* Set WSEC/RATE field */
362 wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT)
363 & BCM43xx_TXHDR_RATE_MASK;
364
365 /* Generate the RTS/CTS packet, if required. */
366 /* FIXME: We should first try with CTS-to-self,
367 * if we are on 80211g. If we get too many
368 * failures (hidden nodes), we should switch back to RTS/CTS.
369 */
370 if (0/*FIXME txctl->use_rts_cts*/) {
371 bcm43xx_generate_rts(phy, txhdr, &flags,
372 0/*FIXME txctl->rts_cts_rate*/,
373 wireless_header);
374 }
375
376 txhdr->flags = cpu_to_le16(flags);
377 txhdr->control = cpu_to_le16(control);
378 txhdr->wsec_rate = cpu_to_le16(wsec_rate);
379}
380
381static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
382 u8 in_rssi, int ofdm,
383 int adjust_2053, int adjust_2050)
384{
385 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
386 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
387 s32 tmp;
388
389 switch (radio->version) {
390 case 0x2050:
391 if (ofdm) {
392 tmp = in_rssi;
393 if (tmp > 127)
394 tmp -= 256;
395 tmp *= 73;
396 tmp /= 64;
397 if (adjust_2050)
398 tmp += 25;
399 else
400 tmp -= 3;
401 } else {
402 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
403 if (in_rssi > 63)
404 in_rssi = 63;
405 tmp = radio->nrssi_lt[in_rssi];
406 tmp = 31 - tmp;
407 tmp *= -131;
408 tmp /= 128;
409 tmp -= 57;
410 } else {
411 tmp = in_rssi;
412 tmp = 31 - tmp;
413 tmp *= -149;
414 tmp /= 128;
415 tmp -= 68;
416 }
417 if (phy->type == BCM43xx_PHYTYPE_G &&
418 adjust_2050)
419 tmp += 25;
420 }
421 break;
422 case 0x2060:
423 if (in_rssi > 127)
424 tmp = in_rssi - 256;
425 else
426 tmp = in_rssi;
427 break;
428 default:
429 tmp = in_rssi;
430 tmp -= 11;
431 tmp *= 103;
432 tmp /= 64;
433 if (adjust_2053)
434 tmp -= 109;
435 else
436 tmp -= 83;
437 }
438
439 return (s8)tmp;
440}
441
442//TODO
443#if 0
444static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
445 u8 in_rssi)
446{
447 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
448 s8 ret;
449
450 if (phy->type == BCM43xx_PHYTYPE_A) {
451 //TODO: Incomplete specs.
452 ret = 0;
453 } else
454 ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
455
456 return ret;
457}
458#endif
459
460int bcm43xx_rx(struct bcm43xx_private *bcm,
461 struct sk_buff *skb,
462 struct bcm43xx_rxhdr *rxhdr)
463{
464 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
465 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
466 struct bcm43xx_plcp_hdr4 *plcp;
467 struct ieee80211_rx_stats stats;
468 struct ieee80211_hdr_4addr *wlhdr;
469 u16 frame_ctl;
470 int is_packet_for_us = 0;
471 int err = -EINVAL;
472 const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
473 const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
474 const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
475 const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
476
477 if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
478 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
479 /* Skip two unknown bytes and the PLCP header. */
480 skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
481 } else {
482 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
483 /* Skip the PLCP header. */
484 skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
485 }
486 /* The SKB contains the PAYLOAD (wireless header + data)
487 * at this point. The FCS at the end is stripped.
488 */
489
490 memset(&stats, 0, sizeof(stats));
491 stats.mac_time = le16_to_cpu(rxhdr->mactime);
492 stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
493 !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
494 !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
495 stats.signal = rxhdr->signal_quality; //FIXME
496//TODO stats.noise =
497 if (is_ofdm)
498 stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
499 else
500 stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
501//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
502 stats.received_channel = radio->channel;
503//TODO stats.control =
504 stats.mask = IEEE80211_STATMASK_SIGNAL |
505//TODO IEEE80211_STATMASK_NOISE |
506 IEEE80211_STATMASK_RATE |
507 IEEE80211_STATMASK_RSSI;
508 if (phy->type == BCM43xx_PHYTYPE_A)
509 stats.freq = IEEE80211_52GHZ_BAND;
510 else
511 stats.freq = IEEE80211_24GHZ_BAND;
512 stats.len = skb->len;
513
514 bcm->stats.last_rx = jiffies;
515 if (bcm->ieee->iw_mode == IW_MODE_MONITOR) {
516 err = ieee80211_rx(bcm->ieee, skb, &stats);
517 return (err == 0) ? -EINVAL : 0;
518 }
519
520 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
521
522 switch (bcm->ieee->iw_mode) {
523 case IW_MODE_ADHOC:
524 if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
525 memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
526 is_broadcast_ether_addr(wlhdr->addr1) ||
527 is_multicast_ether_addr(wlhdr->addr1) ||
528 bcm->net_dev->flags & IFF_PROMISC)
529 is_packet_for_us = 1;
530 break;
531 case IW_MODE_INFRA:
532 default:
533 /* When receiving multicast or broadcast packets, filter out
534 the packets we send ourself; we shouldn't see those */
535 if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
536 memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
537 (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
538 (is_broadcast_ether_addr(wlhdr->addr1) ||
539 is_multicast_ether_addr(wlhdr->addr1) ||
540 bcm->net_dev->flags & IFF_PROMISC)))
541 is_packet_for_us = 1;
542 break;
543 }
544
545 frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
546 if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
547 frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
548 wlhdr->frame_ctl = cpu_to_le16(frame_ctl);
549 /* trim IV and ICV */
550 /* FIXME: this must be done only for WEP encrypted packets */
551 if (skb->len < 32) {
552 dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
553 "set and length < 32)\n");
554 return -EINVAL;
555 } else {
556 memmove(skb->data + 4, skb->data, 24);
557 skb_pull(skb, 4);
558 skb_trim(skb, skb->len - 4);
559 stats.len -= 8;
560 }
561 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
562 }
563
564 switch (WLAN_FC_GET_TYPE(frame_ctl)) {
565 case IEEE80211_FTYPE_MGMT:
566 ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
567 break;
568 case IEEE80211_FTYPE_DATA:
569 if (is_packet_for_us) {
570 err = ieee80211_rx(bcm->ieee, skb, &stats);
571 err = (err == 0) ? -EINVAL : 0;
572 }
573 break;
574 case IEEE80211_FTYPE_CTL:
575 break;
576 default:
577 assert(0);
578 return -EINVAL;
579 }
580
581 return err;
582}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
new file mode 100644
index 000000000000..2aed19e35c77
--- /dev/null
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
@@ -0,0 +1,156 @@
1#ifndef BCM43xx_XMIT_H_
2#define BCM43xx_XMIT_H_
3
4#include "bcm43xx_main.h"
5
6
7#define _bcm43xx_declare_plcp_hdr(size) \
8 struct bcm43xx_plcp_hdr##size { \
9 union { \
10 __le32 data; \
11 __u8 raw[size]; \
12 } __attribute__((__packed__)); \
13 } __attribute__((__packed__))
14
15/* struct bcm43xx_plcp_hdr4 */
16_bcm43xx_declare_plcp_hdr(4);
17/* struct bcm43xx_plcp_hdr6 */
18_bcm43xx_declare_plcp_hdr(6);
19
20#undef _bcm43xx_declare_plcp_hdr
21
22/* Device specific TX header. To be prepended to TX frames. */
23struct bcm43xx_txhdr {
24 union {
25 struct {
26 __le16 flags;
27 __le16 wsec_rate;
28 __le16 frame_control;
29 u16 unknown_zeroed_0;
30 __le16 control;
31 u8 wep_iv[10];
32 u8 unknown_wsec_tkip_data[3]; //FIXME
33 PAD_BYTES(3);
34 u8 mac1[6];
35 u16 unknown_zeroed_1;
36 struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp;
37 __le16 rts_cts_dur_fallback;
38 struct bcm43xx_plcp_hdr4 fallback_plcp;
39 __le16 fallback_dur_id;
40 PAD_BYTES(2);
41 __le16 cookie;
42 __le16 unknown_scb_stuff; //FIXME
43 struct bcm43xx_plcp_hdr6 rts_cts_plcp;
44 __le16 rts_cts_frame_control;
45 __le16 rts_cts_dur;
46 u8 rts_cts_mac1[6];
47 u8 rts_cts_mac2[6];
48 PAD_BYTES(2);
49 struct bcm43xx_plcp_hdr6 plcp;
50 } __attribute__((__packed__));
51 u8 raw[82];
52 } __attribute__((__packed__));
53} __attribute__((__packed__));
54
55/* Values/Masks for the device TX header */
56#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001
57#define BCM43xx_TXHDRFLAG_RTSCTS 0x0002
58#define BCM43xx_TXHDRFLAG_RTS 0x0004
59#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008
60#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020
61#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM 0x0080
62#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100
63#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM 0x0200
64#define BCM43xx_TXHDRFLAG_CTS 0x0400
65#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800
66
67#define BCM43xx_TXHDRCTL_OFDM 0x0001
68#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010
69#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030
70#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8
71
72#define BCM43xx_TXHDR_RATE_MASK 0x0F00
73#define BCM43xx_TXHDR_RATE_SHIFT 8
74#define BCM43xx_TXHDR_RTSRATE_MASK 0xF000
75#define BCM43xx_TXHDR_RTSRATE_SHIFT 12
76#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0
77#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4
78#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003
79#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0
80
81void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
82 struct bcm43xx_txhdr *txhdr,
83 const unsigned char *fragment_data,
84 const unsigned int fragment_len,
85 const int is_first_fragment,
86 const u16 cookie);
87
88/* RX header as received from the hardware. */
89struct bcm43xx_rxhdr {
90 /* Frame Length. Must be generated explicitely in PIO mode. */
91 __le16 frame_length;
92 PAD_BYTES(2);
93 /* Flags field 1 */
94 __le16 flags1;
95 u8 rssi;
96 u8 signal_quality;
97 PAD_BYTES(2);
98 /* Flags field 3 */
99 __le16 flags3;
100 /* Flags field 2 */
101 __le16 flags2;
102 /* Lower 16bits of the TSF at the time the frame started. */
103 __le16 mactime;
104 PAD_BYTES(14);
105} __attribute__((__packed__));
106
107#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0)
108/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */
109#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7)
110#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14)
111
112#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0)
113#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2)
114/*FIXME: WEP related flags */
115
116#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10)
117
118/* Transmit Status as received from the hardware. */
119struct bcm43xx_hwxmitstatus {
120 PAD_BYTES(4);
121 __le16 cookie;
122 u8 flags;
123 u8 cnt1:4,
124 cnt2:4;
125 PAD_BYTES(2);
126 __le16 seq;
127 __le16 unknown; //FIXME
128} __attribute__((__packed__));
129
130/* Transmit Status in CPU byteorder. */
131struct bcm43xx_xmitstatus {
132 u16 cookie;
133 u8 flags;
134 u8 cnt1:4,
135 cnt2:4;
136 u16 seq;
137 u16 unknown; //FIXME
138};
139
140#define BCM43xx_TXSTAT_FLAG_ACK 0x01
141//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02
142//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04
143//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08
144//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10
145#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20
146//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40
147//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80
148
149u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate);
150u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate);
151
152int bcm43xx_rx(struct bcm43xx_private *bcm,
153 struct sk_buff *skb,
154 struct bcm43xx_rxhdr *rxhdr);
155
156#endif /* BCM43xx_XMIT_H_ */