aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43legacy')
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig89
-rw-r--r--drivers/net/wireless/b43legacy/Makefile14
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h829
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.c505
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.h89
-rw-r--r--drivers/net/wireless/b43legacy/dma.c1565
-rw-r--r--drivers/net/wireless/b43legacy/dma.h367
-rw-r--r--drivers/net/wireless/b43legacy/ilt.c336
-rw-r--r--drivers/net/wireless/b43legacy/ilt.h34
-rw-r--r--drivers/net/wireless/b43legacy/leds.c302
-rw-r--r--drivers/net/wireless/b43legacy/leds.h56
-rw-r--r--drivers/net/wireless/b43legacy/main.c3805
-rw-r--r--drivers/net/wireless/b43legacy/main.h147
-rw-r--r--drivers/net/wireless/b43legacy/phy.c2265
-rw-r--r--drivers/net/wireless/b43legacy/phy.h219
-rw-r--r--drivers/net/wireless/b43legacy/pio.c668
-rw-r--r--drivers/net/wireless/b43legacy/pio.h172
-rw-r--r--drivers/net/wireless/b43legacy/radio.c2131
-rw-r--r--drivers/net/wireless/b43legacy/radio.h98
-rw-r--r--drivers/net/wireless/b43legacy/sysfs.c238
-rw-r--r--drivers/net/wireless/b43legacy/sysfs.h9
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c642
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h259
23 files changed, 14839 insertions, 0 deletions
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
new file mode 100644
index 00000000000..7e23ec23fc9
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -0,0 +1,89 @@
1config B43LEGACY
2 tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)"
3 depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
4 select SSB
5 select FW_LOADER
6 select HW_RANDOM
7 ---help---
8 b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and
9 BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the
10 Linksys WPC54G V1 PCMCIA devices.
11
12 Newer 802.11g and 802.11a devices need b43.
13
14 It is safe to include both b43 and b43legacy as the underlying glue
15 layer will automatically load the correct version for your device.
16
17 This driver uses V3 firmware, which must be installed separately using
18 b43-fwcutter.
19
20 This driver can be built as a module (recommended) that will be
21 called "b43legacy". If unsure, say M.
22
23# Auto-select SSB PCI-HOST support, if possible
24config B43LEGACY_PCI_AUTOSELECT
25 bool
26 depends on B43LEGACY && SSB_PCIHOST_POSSIBLE
27 select SSB_PCIHOST
28 default y
29
30# Auto-select SSB PCICORE driver, if possible
31config B43LEGACY_PCICORE_AUTOSELECT
32 bool
33 depends on B43LEGACY && SSB_DRIVER_PCICORE_POSSIBLE
34 select SSB_DRIVER_PCICORE
35 default y
36
37config B43LEGACY_DEBUG
38 bool "Broadcom 43xx-legacy debugging"
39 depends on B43LEGACY
40 default y
41 ---help---
42 Say Y, because this information will help you get the driver running.
43 This option generates a minimum of log output.
44
45config B43LEGACY_DMA
46 bool
47 depends on B43LEGACY
48
49config B43LEGACY_PIO
50 bool
51 depends on B43LEGACY
52
53choice
54 prompt "Broadcom 43xx-legacy data transfer mode"
55 depends on B43LEGACY
56 default B43LEGACY_DMA_AND_PIO_MODE
57
58config B43LEGACY_DMA_AND_PIO_MODE
59 bool "DMA + PIO"
60 select B43LEGACY_DMA
61 select B43LEGACY_PIO
62 ---help---
63 Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
64 data transfer modes. The mode actually used is selectable through
65 the module parameter "pio". With pio=0 as a module parameter, the
66 default DMA is used, otherwise PIO is used.
67
68 If unsure, choose this option.
69
70config B43LEGACY_DMA_MODE
71 bool "DMA (Direct Memory Access) only"
72 select B43LEGACY_DMA
73 ---help---
74 Only include Direct Memory Access (DMA).
75 This reduces the size of the driver module, by omitting the PIO code.
76
77config B43LEGACY_PIO_MODE
78 bool "PIO (Programmed I/O) only"
79 select B43LEGACY_PIO
80 ---help---
81 Only include Programmed I/O (PIO).
82 This reduces the size of the driver module, by omitting the DMA code.
83 Please note that PIO transfers are slow (compared to DMA).
84
85 Also note that not all devices of the b43legacy series support PIO.
86
87 You should use PIO only if DMA does not work for you.
88
89endchoice
diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile
new file mode 100644
index 00000000000..ec3a2482bba
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Makefile
@@ -0,0 +1,14 @@
1obj-$(CONFIG_B43LEGACY) += b43legacy.o
2b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o
3
4b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o
5b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o
6
7b43legacy-objs := main.o \
8 ilt.o \
9 leds.o \
10 phy.o \
11 radio.o \
12 sysfs.o \
13 xmit.o \
14 $(b43legacy-obj-y)
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
new file mode 100644
index 00000000000..34a6277051a
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -0,0 +1,829 @@
1#ifndef B43legacy_H_
2#define B43legacy_H_
3
4#include <linux/hw_random.h>
5#include <linux/kernel.h>
6#include <linux/spinlock.h>
7#include <linux/interrupt.h>
8#include <linux/stringify.h>
9#include <linux/netdevice.h>
10#include <linux/pci.h>
11#include <asm/atomic.h>
12#include <linux/io.h>
13
14#include <linux/ssb/ssb.h>
15#include <linux/ssb/ssb_driver_chipcommon.h>
16
17#include <linux/wireless.h>
18#include <net/mac80211.h>
19
20#include "debugfs.h"
21#include "leds.h"
22#include "phy.h"
23
24
25#define B43legacy_IRQWAIT_MAX_RETRIES 100
26
27#define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */
28
29/* MMIO offsets */
30#define B43legacy_MMIO_DMA0_REASON 0x20
31#define B43legacy_MMIO_DMA0_IRQ_MASK 0x24
32#define B43legacy_MMIO_DMA1_REASON 0x28
33#define B43legacy_MMIO_DMA1_IRQ_MASK 0x2C
34#define B43legacy_MMIO_DMA2_REASON 0x30
35#define B43legacy_MMIO_DMA2_IRQ_MASK 0x34
36#define B43legacy_MMIO_DMA3_REASON 0x38
37#define B43legacy_MMIO_DMA3_IRQ_MASK 0x3C
38#define B43legacy_MMIO_DMA4_REASON 0x40
39#define B43legacy_MMIO_DMA4_IRQ_MASK 0x44
40#define B43legacy_MMIO_DMA5_REASON 0x48
41#define B43legacy_MMIO_DMA5_IRQ_MASK 0x4C
42#define B43legacy_MMIO_MACCTL 0x120
43#define B43legacy_MMIO_STATUS_BITFIELD 0x120
44#define B43legacy_MMIO_STATUS2_BITFIELD 0x124
45#define B43legacy_MMIO_GEN_IRQ_REASON 0x128
46#define B43legacy_MMIO_GEN_IRQ_MASK 0x12C
47#define B43legacy_MMIO_RAM_CONTROL 0x130
48#define B43legacy_MMIO_RAM_DATA 0x134
49#define B43legacy_MMIO_PS_STATUS 0x140
50#define B43legacy_MMIO_RADIO_HWENABLED_HI 0x158
51#define B43legacy_MMIO_SHM_CONTROL 0x160
52#define B43legacy_MMIO_SHM_DATA 0x164
53#define B43legacy_MMIO_SHM_DATA_UNALIGNED 0x166
54#define B43legacy_MMIO_XMITSTAT_0 0x170
55#define B43legacy_MMIO_XMITSTAT_1 0x174
56#define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
57#define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
58
59/* 32-bit DMA */
60#define B43legacy_MMIO_DMA32_BASE0 0x200
61#define B43legacy_MMIO_DMA32_BASE1 0x220
62#define B43legacy_MMIO_DMA32_BASE2 0x240
63#define B43legacy_MMIO_DMA32_BASE3 0x260
64#define B43legacy_MMIO_DMA32_BASE4 0x280
65#define B43legacy_MMIO_DMA32_BASE5 0x2A0
66/* 64-bit DMA */
67#define B43legacy_MMIO_DMA64_BASE0 0x200
68#define B43legacy_MMIO_DMA64_BASE1 0x240
69#define B43legacy_MMIO_DMA64_BASE2 0x280
70#define B43legacy_MMIO_DMA64_BASE3 0x2C0
71#define B43legacy_MMIO_DMA64_BASE4 0x300
72#define B43legacy_MMIO_DMA64_BASE5 0x340
73/* PIO */
74#define B43legacy_MMIO_PIO1_BASE 0x300
75#define B43legacy_MMIO_PIO2_BASE 0x310
76#define B43legacy_MMIO_PIO3_BASE 0x320
77#define B43legacy_MMIO_PIO4_BASE 0x330
78
79#define B43legacy_MMIO_PHY_VER 0x3E0
80#define B43legacy_MMIO_PHY_RADIO 0x3E2
81#define B43legacy_MMIO_PHY0 0x3E6
82#define B43legacy_MMIO_ANTENNA 0x3E8
83#define B43legacy_MMIO_CHANNEL 0x3F0
84#define B43legacy_MMIO_CHANNEL_EXT 0x3F4
85#define B43legacy_MMIO_RADIO_CONTROL 0x3F6
86#define B43legacy_MMIO_RADIO_DATA_HIGH 0x3F8
87#define B43legacy_MMIO_RADIO_DATA_LOW 0x3FA
88#define B43legacy_MMIO_PHY_CONTROL 0x3FC
89#define B43legacy_MMIO_PHY_DATA 0x3FE
90#define B43legacy_MMIO_MACFILTER_CONTROL 0x420
91#define B43legacy_MMIO_MACFILTER_DATA 0x422
92#define B43legacy_MMIO_RCMTA_COUNT 0x43C /* Receive Match Transmitter Addr */
93#define B43legacy_MMIO_RADIO_HWENABLED_LO 0x49A
94#define B43legacy_MMIO_GPIO_CONTROL 0x49C
95#define B43legacy_MMIO_GPIO_MASK 0x49E
96#define B43legacy_MMIO_TSF_0 0x632 /* core rev < 3 only */
97#define B43legacy_MMIO_TSF_1 0x634 /* core rev < 3 only */
98#define B43legacy_MMIO_TSF_2 0x636 /* core rev < 3 only */
99#define B43legacy_MMIO_TSF_3 0x638 /* core rev < 3 only */
100#define B43legacy_MMIO_RNG 0x65A
101#define B43legacy_MMIO_POWERUP_DELAY 0x6A8
102
103/* SPROM boardflags_lo values */
104#define B43legacy_BFL_PACTRL 0x0002
105#define B43legacy_BFL_RSSI 0x0008
106#define B43legacy_BFL_EXTLNA 0x1000
107
108/* GPIO register offset, in both ChipCommon and PCI core. */
109#define B43legacy_GPIO_CONTROL 0x6c
110
111/* SHM Routing */
112#define B43legacy_SHM_SHARED 0x0001
113#define B43legacy_SHM_WIRELESS 0x0002
114#define B43legacy_SHM_HW 0x0004
115#define B43legacy_SHM_UCODE 0x0300
116
117/* SHM Routing modifiers */
118#define B43legacy_SHM_AUTOINC_R 0x0200 /* Read Auto-increment */
119#define B43legacy_SHM_AUTOINC_W 0x0100 /* Write Auto-increment */
120#define B43legacy_SHM_AUTOINC_RW (B43legacy_SHM_AUTOINC_R | \
121 B43legacy_SHM_AUTOINC_W)
122
123/* Misc SHM_SHARED offsets */
124#define B43legacy_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */
125#define B43legacy_SHM_SH_HOSTFLO 0x005E /* Hostflags ucode opts (low) */
126#define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */
127/* SHM_SHARED crypto engine */
128#define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */
129/* SHM_SHARED beacon variables */
130#define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */
131/* SHM_SHARED ACK/CTS control */
132#define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */
133/* SHM_SHARED probe response variables */
134#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
135#define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
136/* SHM_SHARED rate tables */
137/* SHM_SHARED microcode soft registers */
138#define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
139#define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
140#define B43legacy_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
141#define B43legacy_SHM_SH_UCODETIME 0x0006 /* Microcode time */
142
143#define B43legacy_UCODEFLAGS_OFFSET 0x005E
144
145/* Hardware Radio Enable masks */
146#define B43legacy_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
147#define B43legacy_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
148
149/* HostFlags. See b43legacy_hf_read/write() */
150#define B43legacy_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
151#define B43legacy_HF_GDCW 0x00000020 /* G-PHY DV cancel filter */
152#define B43legacy_HF_OFDMPABOOST 0x00000040 /* Enable PA boost OFDM */
153#define B43legacy_HF_EDCF 0x00000100 /* on if WME/MAC suspended */
154
155/* MacFilter offsets. */
156#define B43legacy_MACFILTER_SELF 0x0000
157#define B43legacy_MACFILTER_BSSID 0x0003
158#define B43legacy_MACFILTER_MAC 0x0010
159
160/* PHYVersioning */
161#define B43legacy_PHYTYPE_B 0x01
162#define B43legacy_PHYTYPE_G 0x02
163
164/* PHYRegisters */
165#define B43legacy_PHY_G_LO_CONTROL 0x0810
166#define B43legacy_PHY_ILT_G_CTRL 0x0472
167#define B43legacy_PHY_ILT_G_DATA1 0x0473
168#define B43legacy_PHY_ILT_G_DATA2 0x0474
169#define B43legacy_PHY_G_PCTL 0x0029
170#define B43legacy_PHY_RADIO_BITFIELD 0x0401
171#define B43legacy_PHY_G_CRS 0x0429
172#define B43legacy_PHY_NRSSILT_CTRL 0x0803
173#define B43legacy_PHY_NRSSILT_DATA 0x0804
174
175/* RadioRegisters */
176#define B43legacy_RADIOCTL_ID 0x01
177
178/* MAC Control bitfield */
179#define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */
180#define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */
181#define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */
182#define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */
183#define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
184#define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
185#define B43legacy_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
186#define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */
187
188/* StatusBitField */
189#define B43legacy_SBF_MAC_ENABLED 0x00000001
190#define B43legacy_SBF_CORE_READY 0x00000004
191#define B43legacy_SBF_400 0x00000400 /*FIXME: fix name*/
192#define B43legacy_SBF_XFER_REG_BYTESWAP 0x00010000
193#define B43legacy_SBF_MODE_NOTADHOC 0x00020000
194#define B43legacy_SBF_MODE_AP 0x00040000
195#define B43legacy_SBF_RADIOREG_LOCK 0x00080000
196#define B43legacy_SBF_MODE_MONITOR 0x00400000
197#define B43legacy_SBF_MODE_PROMISC 0x01000000
198#define B43legacy_SBF_PS1 0x02000000
199#define B43legacy_SBF_PS2 0x04000000
200#define B43legacy_SBF_NO_SSID_BCAST 0x08000000
201#define B43legacy_SBF_TIME_UPDATE 0x10000000
202
203/* 802.11 core specific TM State Low flags */
204#define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
205#define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */
206#define B43legacy_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Ctrl Enbl */
207#define B43legacy_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
208#define B43legacy_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
209
210/* 802.11 core specific TM State High flags */
211#define B43legacy_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available */
212#define B43legacy_TMSHIGH_GPHY 0x00010000 /* G-PHY avail (rev >= 5) */
213
214#define B43legacy_UCODEFLAG_AUTODIV 0x0001
215
216/* Generic-Interrupt reasons. */
217#define B43legacy_IRQ_MAC_SUSPENDED 0x00000001
218#define B43legacy_IRQ_BEACON 0x00000002
219#define B43legacy_IRQ_TBTT_INDI 0x00000004 /* Target Beacon Transmit Time */
220#define B43legacy_IRQ_BEACON_TX_OK 0x00000008
221#define B43legacy_IRQ_BEACON_CANCEL 0x00000010
222#define B43legacy_IRQ_ATIM_END 0x00000020
223#define B43legacy_IRQ_PMQ 0x00000040
224#define B43legacy_IRQ_PIO_WORKAROUND 0x00000100
225#define B43legacy_IRQ_MAC_TXERR 0x00000200
226#define B43legacy_IRQ_PHY_TXERR 0x00000800
227#define B43legacy_IRQ_PMEVENT 0x00001000
228#define B43legacy_IRQ_TIMER0 0x00002000
229#define B43legacy_IRQ_TIMER1 0x00004000
230#define B43legacy_IRQ_DMA 0x00008000
231#define B43legacy_IRQ_TXFIFO_FLUSH_OK 0x00010000
232#define B43legacy_IRQ_CCA_MEASURE_OK 0x00020000
233#define B43legacy_IRQ_NOISESAMPLE_OK 0x00040000
234#define B43legacy_IRQ_UCODE_DEBUG 0x08000000
235#define B43legacy_IRQ_RFKILL 0x10000000
236#define B43legacy_IRQ_TX_OK 0x20000000
237#define B43legacy_IRQ_PHY_G_CHANGED 0x40000000
238#define B43legacy_IRQ_TIMEOUT 0x80000000
239
240#define B43legacy_IRQ_ALL 0xFFFFFFFF
241#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \
242 B43legacy_IRQ_BEACON | \
243 B43legacy_IRQ_TBTT_INDI | \
244 B43legacy_IRQ_ATIM_END | \
245 B43legacy_IRQ_PMQ | \
246 B43legacy_IRQ_MAC_TXERR | \
247 B43legacy_IRQ_PHY_TXERR | \
248 B43legacy_IRQ_DMA | \
249 B43legacy_IRQ_TXFIFO_FLUSH_OK | \
250 B43legacy_IRQ_NOISESAMPLE_OK | \
251 B43legacy_IRQ_UCODE_DEBUG | \
252 B43legacy_IRQ_RFKILL | \
253 B43legacy_IRQ_TX_OK)
254
255/* Device specific rate values.
256 * The actual values defined here are (rate_in_mbps * 2).
257 * Some code depends on this. Don't change it. */
258#define B43legacy_CCK_RATE_1MB 2
259#define B43legacy_CCK_RATE_2MB 4
260#define B43legacy_CCK_RATE_5MB 11
261#define B43legacy_CCK_RATE_11MB 22
262#define B43legacy_OFDM_RATE_6MB 12
263#define B43legacy_OFDM_RATE_9MB 18
264#define B43legacy_OFDM_RATE_12MB 24
265#define B43legacy_OFDM_RATE_18MB 36
266#define B43legacy_OFDM_RATE_24MB 48
267#define B43legacy_OFDM_RATE_36MB 72
268#define B43legacy_OFDM_RATE_48MB 96
269#define B43legacy_OFDM_RATE_54MB 108
270/* Convert a b43legacy rate value to a rate in 100kbps */
271#define B43legacy_RATE_TO_100KBPS(rate) (((rate) * 10) / 2)
272
273
274#define B43legacy_DEFAULT_SHORT_RETRY_LIMIT 7
275#define B43legacy_DEFAULT_LONG_RETRY_LIMIT 4
276
277/* Max size of a security key */
278#define B43legacy_SEC_KEYSIZE 16
279/* Security algorithms. */
280enum {
281 B43legacy_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
282 B43legacy_SEC_ALGO_WEP40,
283 B43legacy_SEC_ALGO_TKIP,
284 B43legacy_SEC_ALGO_AES,
285 B43legacy_SEC_ALGO_WEP104,
286 B43legacy_SEC_ALGO_AES_LEGACY,
287};
288
289/* Core Information Registers */
290#define B43legacy_CIR_BASE 0xf00
291#define B43legacy_CIR_SBTPSFLAG (B43legacy_CIR_BASE + 0x18)
292#define B43legacy_CIR_SBIMSTATE (B43legacy_CIR_BASE + 0x90)
293#define B43legacy_CIR_SBINTVEC (B43legacy_CIR_BASE + 0x94)
294#define B43legacy_CIR_SBTMSTATELOW (B43legacy_CIR_BASE + 0x98)
295#define B43legacy_CIR_SBTMSTATEHIGH (B43legacy_CIR_BASE + 0x9c)
296#define B43legacy_CIR_SBIMCONFIGLOW (B43legacy_CIR_BASE + 0xa8)
297#define B43legacy_CIR_SB_ID_HI (B43legacy_CIR_BASE + 0xfc)
298
299/* sbtmstatehigh state flags */
300#define B43legacy_SBTMSTATEHIGH_SERROR 0x00000001
301#define B43legacy_SBTMSTATEHIGH_BUSY 0x00000004
302#define B43legacy_SBTMSTATEHIGH_TIMEOUT 0x00000020
303#define B43legacy_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000
304#define B43legacy_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
305#define B43legacy_SBTMSTATEHIGH_DMA64BIT 0x10000000
306#define B43legacy_SBTMSTATEHIGH_GATEDCLK 0x20000000
307#define B43legacy_SBTMSTATEHIGH_BISTFAILED 0x40000000
308#define B43legacy_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000
309
310/* sbimstate flags */
311#define B43legacy_SBIMSTATE_IB_ERROR 0x20000
312#define B43legacy_SBIMSTATE_TIMEOUT 0x40000
313
314#define PFX KBUILD_MODNAME ": "
315#ifdef assert
316# undef assert
317#endif
318#ifdef CONFIG_B43LEGACY_DEBUG
319# define B43legacy_WARN_ON(expr) \
320 do { \
321 if (unlikely((expr))) { \
322 printk(KERN_INFO PFX "Test (%s) failed at:" \
323 " %s:%d:%s()\n", \
324 #expr, __FILE__, \
325 __LINE__, __FUNCTION__); \
326 } \
327 } while (0)
328# define B43legacy_BUG_ON(expr) \
329 do { \
330 if (unlikely((expr))) { \
331 printk(KERN_INFO PFX "Test (%s) failed\n", \
332 #expr); \
333 BUG_ON(expr); \
334 } \
335 } while (0)
336# define B43legacy_DEBUG 1
337#else
338# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0)
339# define B43legacy_BUG_ON(x) do { /* nothing */ } while (0)
340# define B43legacy_DEBUG 0
341#endif
342
343
344struct net_device;
345struct pci_dev;
346struct b43legacy_dmaring;
347struct b43legacy_pioqueue;
348
349/* The firmware file header */
350#define B43legacy_FW_TYPE_UCODE 'u'
351#define B43legacy_FW_TYPE_PCM 'p'
352#define B43legacy_FW_TYPE_IV 'i'
353struct b43legacy_fw_header {
354 /* File type */
355 u8 type;
356 /* File format version */
357 u8 ver;
358 u8 __padding[2];
359 /* Size of the data. For ucode and PCM this is in bytes.
360 * For IV this is number-of-ivs. */
361 __be32 size;
362} __attribute__((__packed__));
363
364/* Initial Value file format */
365#define B43legacy_IV_OFFSET_MASK 0x7FFF
366#define B43legacy_IV_32BIT 0x8000
367struct b43legacy_iv {
368 __be16 offset_size;
369 union {
370 __be16 d16;
371 __be32 d32;
372 } data __attribute__((__packed__));
373} __attribute__((__packed__));
374
375#define B43legacy_PHYMODE(phytype) (1 << (phytype))
376#define B43legacy_PHYMODE_B B43legacy_PHYMODE \
377 ((B43legacy_PHYTYPE_B))
378#define B43legacy_PHYMODE_G B43legacy_PHYMODE \
379 ((B43legacy_PHYTYPE_G))
380
381/* Value pair to measure the LocalOscillator. */
382struct b43legacy_lopair {
383 s8 low;
384 s8 high;
385 u8 used:1;
386};
387#define B43legacy_LO_COUNT (14*4)
388
389struct b43legacy_phy {
390 /* Possible PHYMODEs on this PHY */
391 u8 possible_phymodes;
392 /* GMODE bit enabled in MACCTL? */
393 bool gmode;
394 /* Possible ieee80211 subsystem hwmodes for this PHY.
395 * Which mode is selected, depends on thr GMODE enabled bit */
396#define B43legacy_MAX_PHYHWMODES 2
397 struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES];
398
399 /* Analog Type */
400 u8 analog;
401 /* B43legacy_PHYTYPE_ */
402 u8 type;
403 /* PHY revision number. */
404 u8 rev;
405
406 u16 antenna_diversity;
407 u16 savedpctlreg;
408 /* Radio versioning */
409 u16 radio_manuf; /* Radio manufacturer */
410 u16 radio_ver; /* Radio version */
411 u8 calibrated:1;
412 u8 radio_rev; /* Radio revision */
413
414 bool radio_on; /* Radio switched on/off */
415 bool locked; /* Only used in b43legacy_phy_{un}lock() */
416 bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
417
418 /* ACI (adjacent channel interference) flags. */
419 bool aci_enable;
420 bool aci_wlan_automatic;
421 bool aci_hw_rssi;
422
423 u16 minlowsig[2];
424 u16 minlowsigpos[2];
425
426 /* LO Measurement Data.
427 * Use b43legacy_get_lopair() to get a value.
428 */
429 struct b43legacy_lopair *_lo_pairs;
430 /* TSSI to dBm table in use */
431 const s8 *tssi2dbm;
432 /* idle TSSI value */
433 s8 idle_tssi;
434 /* Target idle TSSI */
435 int tgt_idle_tssi;
436 /* Current idle TSSI */
437 int cur_idle_tssi;
438
439 /* LocalOscillator control values. */
440 struct b43legacy_txpower_lo_control *lo_control;
441 /* Values from b43legacy_calc_loopback_gain() */
442 s16 max_lb_gain; /* Maximum Loopback gain in hdB */
443 s16 trsw_rx_gain; /* TRSW RX gain in hdB */
444 s16 lna_lod_gain; /* LNA lod */
445 s16 lna_gain; /* LNA */
446 s16 pga_gain; /* PGA */
447
448 /* PHY lock for core.rev < 3
449 * This lock is only used by b43legacy_phy_{un}lock()
450 */
451 spinlock_t lock;
452
453 /* Desired TX power level (in dBm). This is set by the user and
454 * adjusted in b43legacy_phy_xmitpower(). */
455 u8 power_level;
456
457 /* Values from b43legacy_calc_loopback_gain() */
458 u16 loopback_gain[2];
459
460 /* TX Power control values. */
461 /* B/G PHY */
462 struct {
463 /* Current Radio Attenuation for TXpower recalculation. */
464 u16 rfatt;
465 /* Current Baseband Attenuation for TXpower recalculation. */
466 u16 bbatt;
467 /* Current TXpower control value for TXpower recalculation. */
468 u16 txctl1;
469 u16 txctl2;
470 };
471 /* A PHY */
472 struct {
473 u16 txpwr_offset;
474 };
475
476#ifdef CONFIG_B43LEGACY_DEBUG
477 bool manual_txpower_control; /* Manual TX-power control enabled? */
478#endif
479 /* Current Interference Mitigation mode */
480 int interfmode;
481 /* Stack of saved values from the Interference Mitigation code.
482 * Each value in the stack is layed out as follows:
483 * bit 0-11: offset
484 * bit 12-15: register ID
485 * bit 16-32: value
486 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
487 */
488#define B43legacy_INTERFSTACK_SIZE 26
489 u32 interfstack[B43legacy_INTERFSTACK_SIZE];
490
491 /* Saved values from the NRSSI Slope calculation */
492 s16 nrssi[2];
493 s32 nrssislope;
494 /* In memory nrssi lookup table. */
495 s8 nrssi_lt[64];
496
497 /* current channel */
498 u8 channel;
499
500 u16 lofcal;
501
502 u16 initval;
503};
504
505/* Data structures for DMA transmission, per 80211 core. */
506struct b43legacy_dma {
507 struct b43legacy_dmaring *tx_ring0;
508 struct b43legacy_dmaring *tx_ring1;
509 struct b43legacy_dmaring *tx_ring2;
510 struct b43legacy_dmaring *tx_ring3;
511 struct b43legacy_dmaring *tx_ring4;
512 struct b43legacy_dmaring *tx_ring5;
513
514 struct b43legacy_dmaring *rx_ring0;
515 struct b43legacy_dmaring *rx_ring3; /* only on core.rev < 5 */
516};
517
518/* Data structures for PIO transmission, per 80211 core. */
519struct b43legacy_pio {
520 struct b43legacy_pioqueue *queue0;
521 struct b43legacy_pioqueue *queue1;
522 struct b43legacy_pioqueue *queue2;
523 struct b43legacy_pioqueue *queue3;
524};
525
526/* Context information for a noise calculation (Link Quality). */
527struct b43legacy_noise_calculation {
528 u8 channel_at_start;
529 bool calculation_running;
530 u8 nr_samples;
531 s8 samples[8][4];
532};
533
534struct b43legacy_stats {
535 u8 link_noise;
536 /* Store the last TX/RX times here for updating the leds. */
537 unsigned long last_tx;
538 unsigned long last_rx;
539};
540
541struct b43legacy_key {
542 void *keyconf;
543 bool enabled;
544 u8 algorithm;
545};
546
547struct b43legacy_wldev;
548
549/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */
550struct b43legacy_wl {
551 /* Pointer to the active wireless device on this chip */
552 struct b43legacy_wldev *current_dev;
553 /* Pointer to the ieee80211 hardware data structure */
554 struct ieee80211_hw *hw;
555
556 spinlock_t irq_lock; /* locks IRQ */
557 struct mutex mutex; /* locks wireless core state */
558 spinlock_t leds_lock; /* lock for leds */
559
560 /* We can only have one operating interface (802.11 core)
561 * at a time. General information about this interface follows.
562 */
563
564 /* Opaque ID of the operating interface (!= monitor
565 * interface) from the ieee80211 subsystem.
566 * Do not modify.
567 */
568 int if_id;
569 /* MAC address (can be NULL). */
570 const u8 *mac_addr;
571 /* Current BSSID (can be NULL). */
572 const u8 *bssid;
573 /* Interface type. (IEEE80211_IF_TYPE_XXX) */
574 int if_type;
575 /* Counter of active monitor interfaces. */
576 int monitor;
577 /* Is the card operating in AP, STA or IBSS mode? */
578 bool operating;
579 /* Promisc mode active?
580 * Note that (monitor != 0) implies promisc.
581 */
582 bool promisc;
583 /* Stats about the wireless interface */
584 struct ieee80211_low_level_stats ieee_stats;
585
586 struct hwrng rng;
587 u8 rng_initialized;
588 char rng_name[30 + 1];
589
590 /* List of all wireless devices on this chip */
591 struct list_head devlist;
592 u8 nr_devs;
593};
594
595/* Pointers to the firmware data and meta information about it. */
596struct b43legacy_firmware {
597 /* Microcode */
598 const struct firmware *ucode;
599 /* PCM code */
600 const struct firmware *pcm;
601 /* Initial MMIO values for the firmware */
602 const struct firmware *initvals;
603 /* Initial MMIO values for the firmware, band-specific */
604 const struct firmware *initvals_band;
605 /* Firmware revision */
606 u16 rev;
607 /* Firmware patchlevel */
608 u16 patch;
609};
610
611/* Device (802.11 core) initialization status. */
612enum {
613 B43legacy_STAT_UNINIT = 0, /* Uninitialized. */
614 B43legacy_STAT_INITIALIZED = 1, /* Initialized, not yet started. */
615 B43legacy_STAT_STARTED = 2, /* Up and running. */
616};
617#define b43legacy_status(wldev) atomic_read(&(wldev)->__init_status)
618#define b43legacy_set_status(wldev, stat) do { \
619 atomic_set(&(wldev)->__init_status, (stat)); \
620 smp_wmb(); \
621 } while (0)
622
623/* *** --- HOW LOCKING WORKS IN B43legacy --- ***
624 *
625 * You should always acquire both, wl->mutex and wl->irq_lock unless:
626 * - You don't need to acquire wl->irq_lock, if the interface is stopped.
627 * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
628 * and packet TX path (and _ONLY_ there.)
629 */
630
631/* Data structure for one wireless device (802.11 core) */
632struct b43legacy_wldev {
633 struct ssb_device *dev;
634 struct b43legacy_wl *wl;
635
636 /* The device initialization status.
637 * Use b43legacy_status() to query. */
638 atomic_t __init_status;
639 /* Saved init status for handling suspend. */
640 int suspend_init_status;
641
642 bool __using_pio; /* Using pio rather than dma. */
643 bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
644 bool reg124_set_0x4; /* Variable to keep track of IRQ. */
645 bool short_preamble; /* TRUE if using short preamble. */
646 bool short_slot; /* TRUE if using short slot timing. */
647 bool radio_hw_enable; /* State of radio hardware enable bit. */
648
649 /* PHY/Radio device. */
650 struct b43legacy_phy phy;
651 union {
652 /* DMA engines. */
653 struct b43legacy_dma dma;
654 /* PIO engines. */
655 struct b43legacy_pio pio;
656 };
657
658 /* Various statistics about the physical device. */
659 struct b43legacy_stats stats;
660
661#define B43legacy_NR_LEDS 4
662 struct b43legacy_led leds[B43legacy_NR_LEDS];
663
664 /* Reason code of the last interrupt. */
665 u32 irq_reason;
666 u32 dma_reason[6];
667 /* saved irq enable/disable state bitfield. */
668 u32 irq_savedstate;
669 /* Link Quality calculation context. */
670 struct b43legacy_noise_calculation noisecalc;
671 /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
672 int mac_suspended;
673
674 /* Interrupt Service Routine tasklet (bottom-half) */
675 struct tasklet_struct isr_tasklet;
676
677 /* Periodic tasks */
678 struct delayed_work periodic_work;
679 unsigned int periodic_state;
680
681 struct work_struct restart_work;
682
683 /* encryption/decryption */
684 u16 ktp; /* Key table pointer */
685 u8 max_nr_keys;
686 struct b43legacy_key key[58];
687
688 /* Cached beacon template while uploading the template. */
689 struct sk_buff *cached_beacon;
690
691 /* Firmware data */
692 struct b43legacy_firmware fw;
693
694 /* Devicelist in struct b43legacy_wl (all 802.11 cores) */
695 struct list_head list;
696
697 /* Debugging stuff follows. */
698#ifdef CONFIG_B43LEGACY_DEBUG
699 struct b43legacy_dfsentry *dfsentry;
700#endif
701};
702
703
704static inline
705struct b43legacy_wl *hw_to_b43legacy_wl(struct ieee80211_hw *hw)
706{
707 return hw->priv;
708}
709
710/* Helper function, which returns a boolean.
711 * TRUE, if PIO is used; FALSE, if DMA is used.
712 */
713#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
714static inline
715int b43legacy_using_pio(struct b43legacy_wldev *dev)
716{
717 return dev->__using_pio;
718}
719#elif defined(CONFIG_B43LEGACY_DMA)
720static inline
721int b43legacy_using_pio(struct b43legacy_wldev *dev)
722{
723 return 0;
724}
725#elif defined(CONFIG_B43LEGACY_PIO)
726static inline
727int b43legacy_using_pio(struct b43legacy_wldev *dev)
728{
729 return 1;
730}
731#else
732# error "Using neither DMA nor PIO? Confused..."
733#endif
734
735
736static inline
737struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev)
738{
739 struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
740 return ssb_get_drvdata(ssb_dev);
741}
742
743/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
744static inline
745int b43legacy_is_mode(struct b43legacy_wl *wl, int type)
746{
747 if (type == IEEE80211_IF_TYPE_MNTR)
748 return !!(wl->monitor);
749 return (wl->operating &&
750 wl->if_type == type);
751}
752
753static inline
754bool is_bcm_board_vendor(struct b43legacy_wldev *dev)
755{
756 return (dev->dev->bus->boardinfo.vendor == PCI_VENDOR_ID_BROADCOM);
757}
758
759static inline
760u16 b43legacy_read16(struct b43legacy_wldev *dev, u16 offset)
761{
762 return ssb_read16(dev->dev, offset);
763}
764
765static inline
766void b43legacy_write16(struct b43legacy_wldev *dev, u16 offset, u16 value)
767{
768 ssb_write16(dev->dev, offset, value);
769}
770
771static inline
772u32 b43legacy_read32(struct b43legacy_wldev *dev, u16 offset)
773{
774 return ssb_read32(dev->dev, offset);
775}
776
777static inline
778void b43legacy_write32(struct b43legacy_wldev *dev, u16 offset, u32 value)
779{
780 ssb_write32(dev->dev, offset, value);
781}
782
783static inline
784struct b43legacy_lopair *b43legacy_get_lopair(struct b43legacy_phy *phy,
785 u16 radio_attenuation,
786 u16 baseband_attenuation)
787{
788 return phy->_lo_pairs + (radio_attenuation
789 + 14 * (baseband_attenuation / 2));
790}
791
792
793
794/* Message printing */
795void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
796 __attribute__((format(printf, 2, 3)));
797void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
798 __attribute__((format(printf, 2, 3)));
799void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
800 __attribute__((format(printf, 2, 3)));
801#if B43legacy_DEBUG
802void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
803 __attribute__((format(printf, 2, 3)));
804#else /* DEBUG */
805# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0)
806#endif /* DEBUG */
807
808
809/** Limit a value between two limits */
810#ifdef limit_value
811# undef limit_value
812#endif
813#define limit_value(value, min, max) \
814 ({ \
815 typeof(value) __value = (value); \
816 typeof(value) __min = (min); \
817 typeof(value) __max = (max); \
818 if (__value < __min) \
819 __value = __min; \
820 else if (__value > __max) \
821 __value = __max; \
822 __value; \
823 })
824
825/* Macros for printing a value in Q5.2 format */
826#define Q52_FMT "%u.%u"
827#define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4)
828
829#endif /* B43legacy_H_ */
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
new file mode 100644
index 00000000000..eefa6fb7968
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -0,0 +1,505 @@
1/*
2
3 Broadcom B43legacy wireless driver
4
5 debugfs driver debugging code
6
7 Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.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 <linux/fs.h>
27#include <linux/debugfs.h>
28#include <linux/slab.h>
29#include <linux/netdevice.h>
30#include <linux/pci.h>
31#include <linux/mutex.h>
32
33#include "b43legacy.h"
34#include "main.h"
35#include "debugfs.h"
36#include "dma.h"
37#include "pio.h"
38#include "xmit.h"
39
40
41/* The root directory. */
42static struct dentry *rootdir;
43
44struct b43legacy_debugfs_fops {
45 ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize);
46 int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count);
47 struct file_operations fops;
48 /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */
49 size_t file_struct_offset;
50 /* Take wl->irq_lock before calling read/write? */
51 bool take_irqlock;
52};
53
54static inline
55struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev,
56 const struct b43legacy_debugfs_fops *dfops)
57{
58 void *p;
59
60 p = dev->dfsentry;
61 p += dfops->file_struct_offset;
62
63 return p;
64}
65
66
67#define fappend(fmt, x...) \
68 do { \
69 if (bufsize - count) \
70 count += snprintf(buf + count, \
71 bufsize - count, \
72 fmt , ##x); \
73 else \
74 printk(KERN_ERR "b43legacy: fappend overflow\n"); \
75 } while (0)
76
77
78/* wl->irq_lock is locked */
79static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
80{
81 ssize_t count = 0;
82 u64 tsf;
83
84 b43legacy_tsf_read(dev, &tsf);
85 fappend("0x%08x%08x\n",
86 (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
87 (unsigned int)(tsf & 0xFFFFFFFFULL));
88
89 return count;
90}
91
92/* wl->irq_lock is locked */
93static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
94{
95 u64 tsf;
96
97 if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
98 return -EINVAL;
99 b43legacy_tsf_write(dev, tsf);
100
101 return 0;
102}
103
104/* wl->irq_lock is locked */
105static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
106{
107 ssize_t count = 0;
108 int i;
109
110 for (i = 0; i < 64; i++) {
111 fappend("r%d = 0x%04x\n", i,
112 b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i));
113 }
114
115 return count;
116}
117
118/* wl->irq_lock is locked */
119static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
120{
121 ssize_t count = 0;
122 int i;
123 u16 tmp;
124 __le16 *le16buf = (__le16 *)buf;
125
126 for (i = 0; i < 0x1000; i++) {
127 if (bufsize <= 0)
128 break;
129 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i);
130 le16buf[i] = cpu_to_le16(tmp);
131 count += sizeof(tmp);
132 bufsize -= sizeof(tmp);
133 }
134
135 return count;
136}
137
138static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
139{
140 struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog;
141 ssize_t count = 0;
142 unsigned long flags;
143 int i, idx;
144 struct b43legacy_txstatus *stat;
145
146 spin_lock_irqsave(&log->lock, flags);
147 if (log->end < 0) {
148 fappend("Nothing transmitted, yet\n");
149 goto out_unlock;
150 }
151 fappend("b43legacy TX status reports:\n\n"
152 "index | cookie | seq | phy_stat | frame_count | "
153 "rts_count | supp_reason | pm_indicated | "
154 "intermediate | for_ampdu | acked\n" "---\n");
155 i = log->end + 1;
156 idx = 0;
157 while (1) {
158 if (i == B43legacy_NR_LOGGED_TXSTATUS)
159 i = 0;
160 stat = &(log->log[i]);
161 if (stat->cookie) {
162 fappend("%03d | "
163 "0x%04X | 0x%04X | 0x%02X | "
164 "0x%X | 0x%X | "
165 "%u | %u | "
166 "%u | %u | %u\n",
167 idx,
168 stat->cookie, stat->seq, stat->phy_stat,
169 stat->frame_count, stat->rts_count,
170 stat->supp_reason, stat->pm_indicated,
171 stat->intermediate, stat->for_ampdu,
172 stat->acked);
173 idx++;
174 }
175 if (i == log->end)
176 break;
177 i++;
178 }
179out_unlock:
180 spin_unlock_irqrestore(&log->lock, flags);
181
182 return count;
183}
184
185/* wl->irq_lock is locked */
186static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
187{
188 int err = 0;
189
190 if (count > 0 && buf[0] == '1') {
191 b43legacy_controller_restart(dev, "manually restarted");
192 } else
193 err = -EINVAL;
194
195 return err;
196}
197
198#undef fappend
199
200static int b43legacy_debugfs_open(struct inode *inode, struct file *file)
201{
202 file->private_data = inode->i_private;
203 return 0;
204}
205
206static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
207 size_t count, loff_t *ppos)
208{
209 struct b43legacy_wldev *dev;
210 struct b43legacy_debugfs_fops *dfops;
211 struct b43legacy_dfs_file *dfile;
212 ssize_t ret = 0;
213 char *buf;
214 const size_t bufsize = 1024 * 128;
215 const size_t buforder = get_order(bufsize);
216 int err = 0;
217
218 if (!count)
219 return 0;
220 dev = file->private_data;
221 if (!dev)
222 return -ENODEV;
223
224 mutex_lock(&dev->wl->mutex);
225 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
226 err = -ENODEV;
227 goto out_unlock;
228 }
229
230 dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
231 if (!dfops->read) {
232 err = -ENOSYS;
233 goto out_unlock;
234 }
235 dfile = fops_to_dfs_file(dev, dfops);
236
237 if (!dfile->buffer) {
238 buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
239 if (!buf) {
240 err = -ENOMEM;
241 goto out_unlock;
242 }
243 memset(buf, 0, bufsize);
244 if (dfops->take_irqlock) {
245 spin_lock_irq(&dev->wl->irq_lock);
246 ret = dfops->read(dev, buf, bufsize);
247 spin_unlock_irq(&dev->wl->irq_lock);
248 } else
249 ret = dfops->read(dev, buf, bufsize);
250 if (ret <= 0) {
251 free_pages((unsigned long)buf, buforder);
252 err = ret;
253 goto out_unlock;
254 }
255 dfile->data_len = ret;
256 dfile->buffer = buf;
257 }
258
259 ret = simple_read_from_buffer(userbuf, count, ppos,
260 dfile->buffer,
261 dfile->data_len);
262 if (*ppos >= dfile->data_len) {
263 free_pages((unsigned long)dfile->buffer, buforder);
264 dfile->buffer = NULL;
265 dfile->data_len = 0;
266 }
267out_unlock:
268 mutex_unlock(&dev->wl->mutex);
269
270 return err ? err : ret;
271}
272
273static ssize_t b43legacy_debugfs_write(struct file *file,
274 const char __user *userbuf,
275 size_t count, loff_t *ppos)
276{
277 struct b43legacy_wldev *dev;
278 struct b43legacy_debugfs_fops *dfops;
279 char *buf;
280 int err = 0;
281
282 if (!count)
283 return 0;
284 if (count > PAGE_SIZE)
285 return -E2BIG;
286 dev = file->private_data;
287 if (!dev)
288 return -ENODEV;
289
290 mutex_lock(&dev->wl->mutex);
291 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
292 err = -ENODEV;
293 goto out_unlock;
294 }
295
296 dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
297 if (!dfops->write) {
298 err = -ENOSYS;
299 goto out_unlock;
300 }
301
302 buf = (char *)get_zeroed_page(GFP_KERNEL);
303 if (!buf) {
304 err = -ENOMEM;
305 goto out_unlock;
306 }
307 if (copy_from_user(buf, userbuf, count)) {
308 err = -EFAULT;
309 goto out_freepage;
310 }
311 if (dfops->take_irqlock) {
312 spin_lock_irq(&dev->wl->irq_lock);
313 err = dfops->write(dev, buf, count);
314 spin_unlock_irq(&dev->wl->irq_lock);
315 } else
316 err = dfops->write(dev, buf, count);
317 if (err)
318 goto out_freepage;
319
320out_freepage:
321 free_page((unsigned long)buf);
322out_unlock:
323 mutex_unlock(&dev->wl->mutex);
324
325 return err ? err : count;
326}
327
328
329#define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
330 static struct b43legacy_debugfs_fops fops_##name = { \
331 .read = _read, \
332 .write = _write, \
333 .fops = { \
334 .open = b43legacy_debugfs_open, \
335 .read = b43legacy_debugfs_read, \
336 .write = b43legacy_debugfs_write, \
337 }, \
338 .file_struct_offset = offsetof(struct b43legacy_dfsentry, \
339 file_##name), \
340 .take_irqlock = _take_irqlock, \
341 }
342
343B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
344B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
345B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
346B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
347B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
348
349
350int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature)
351{
352 return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
353}
354
355static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev)
356{
357 struct b43legacy_dfsentry *e = dev->dfsentry;
358 int i;
359
360 for (i = 0; i < __B43legacy_NR_DYNDBG; i++)
361 debugfs_remove(e->dyn_debug_dentries[i]);
362}
363
364static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev)
365{
366 struct b43legacy_dfsentry *e = dev->dfsentry;
367 struct dentry *d;
368
369#define add_dyn_dbg(name, id, initstate) do { \
370 e->dyn_debug[id] = (initstate); \
371 d = debugfs_create_bool(name, 0600, e->subdir, \
372 &(e->dyn_debug[id])); \
373 if (!IS_ERR(d)) \
374 e->dyn_debug_dentries[id] = d; \
375 } while (0)
376
377 add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, 0);
378 add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, 0);
379 add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, 0);
380 add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, 0);
381 add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, 0);
382
383#undef add_dyn_dbg
384}
385
386void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev)
387{
388 struct b43legacy_dfsentry *e;
389 struct b43legacy_txstatus_log *log;
390 char devdir[16];
391
392 B43legacy_WARN_ON(!dev);
393 e = kzalloc(sizeof(*e), GFP_KERNEL);
394 if (!e) {
395 b43legacyerr(dev->wl, "debugfs: add device OOM\n");
396 return;
397 }
398 e->dev = dev;
399 log = &e->txstatlog;
400 log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS,
401 sizeof(struct b43legacy_txstatus), GFP_KERNEL);
402 if (!log->log) {
403 b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n");
404 kfree(e);
405 return;
406 }
407 log->end = -1;
408 spin_lock_init(&log->lock);
409
410 dev->dfsentry = e;
411
412 snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
413 e->subdir = debugfs_create_dir(devdir, rootdir);
414 if (!e->subdir || IS_ERR(e->subdir)) {
415 if (e->subdir == ERR_PTR(-ENODEV)) {
416 b43legacydbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
417 "enabled in kernel config\n");
418 } else {
419 b43legacyerr(dev->wl, "debugfs: cannot create %s directory\n",
420 devdir);
421 }
422 dev->dfsentry = NULL;
423 kfree(log->log);
424 kfree(e);
425 return;
426 }
427
428#define ADD_FILE(name, mode) \
429 do { \
430 struct dentry *d; \
431 d = debugfs_create_file(__stringify(name), \
432 mode, e->subdir, dev, \
433 &fops_##name.fops); \
434 e->file_##name.dentry = NULL; \
435 if (!IS_ERR(d)) \
436 e->file_##name.dentry = d; \
437 } while (0)
438
439
440 ADD_FILE(tsf, 0600);
441 ADD_FILE(ucode_regs, 0400);
442 ADD_FILE(shm, 0400);
443 ADD_FILE(txstat, 0400);
444 ADD_FILE(restart, 0200);
445
446#undef ADD_FILE
447
448 b43legacy_add_dynamic_debug(dev);
449}
450
451void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev)
452{
453 struct b43legacy_dfsentry *e;
454
455 if (!dev)
456 return;
457 e = dev->dfsentry;
458 if (!e)
459 return;
460 b43legacy_remove_dynamic_debug(dev);
461
462 debugfs_remove(e->file_tsf.dentry);
463 debugfs_remove(e->file_ucode_regs.dentry);
464 debugfs_remove(e->file_shm.dentry);
465 debugfs_remove(e->file_txstat.dentry);
466 debugfs_remove(e->file_restart.dentry);
467
468 debugfs_remove(e->subdir);
469 kfree(e->txstatlog.log);
470 kfree(e);
471}
472
473void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
474 const struct b43legacy_txstatus *status)
475{
476 struct b43legacy_dfsentry *e = dev->dfsentry;
477 struct b43legacy_txstatus_log *log;
478 struct b43legacy_txstatus *cur;
479 int i;
480
481 if (!e)
482 return;
483 log = &e->txstatlog;
484 B43legacy_WARN_ON(!irqs_disabled());
485 spin_lock(&log->lock);
486 i = log->end + 1;
487 if (i == B43legacy_NR_LOGGED_TXSTATUS)
488 i = 0;
489 log->end = i;
490 cur = &(log->log[i]);
491 memcpy(cur, status, sizeof(*cur));
492 spin_unlock(&log->lock);
493}
494
495void b43legacy_debugfs_init(void)
496{
497 rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
498 if (IS_ERR(rootdir))
499 rootdir = NULL;
500}
501
502void b43legacy_debugfs_exit(void)
503{
504 debugfs_remove(rootdir);
505}
diff --git a/drivers/net/wireless/b43legacy/debugfs.h b/drivers/net/wireless/b43legacy/debugfs.h
new file mode 100644
index 00000000000..ae3b0d0fa84
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.h
@@ -0,0 +1,89 @@
1#ifndef B43legacy_DEBUGFS_H_
2#define B43legacy_DEBUGFS_H_
3
4struct b43legacy_wldev;
5struct b43legacy_txstatus;
6
7enum b43legacy_dyndbg { /* Dynamic debugging features */
8 B43legacy_DBG_XMITPOWER,
9 B43legacy_DBG_DMAOVERFLOW,
10 B43legacy_DBG_DMAVERBOSE,
11 B43legacy_DBG_PWORK_FAST,
12 B43legacy_DBG_PWORK_STOP,
13 __B43legacy_NR_DYNDBG,
14};
15
16
17#ifdef CONFIG_B43LEGACY_DEBUG
18
19struct dentry;
20
21#define B43legacy_NR_LOGGED_TXSTATUS 100
22
23struct b43legacy_txstatus_log {
24 struct b43legacy_txstatus *log;
25 int end;
26 spinlock_t lock; /* lock for debugging */
27};
28
29struct b43legacy_dfs_file {
30 struct dentry *dentry;
31 char *buffer;
32 size_t data_len;
33};
34
35struct b43legacy_dfsentry {
36 struct b43legacy_wldev *dev;
37 struct dentry *subdir;
38
39 struct b43legacy_dfs_file file_tsf;
40 struct b43legacy_dfs_file file_ucode_regs;
41 struct b43legacy_dfs_file file_shm;
42 struct b43legacy_dfs_file file_txstat;
43 struct b43legacy_dfs_file file_txpower_g;
44 struct b43legacy_dfs_file file_restart;
45 struct b43legacy_dfs_file file_loctls;
46
47 struct b43legacy_txstatus_log txstatlog;
48
49 /* Enabled/Disabled list for the dynamic debugging features. */
50 u32 dyn_debug[__B43legacy_NR_DYNDBG];
51 /* Dentries for the dynamic debugging entries. */
52 struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG];
53};
54
55int b43legacy_debug(struct b43legacy_wldev *dev,
56 enum b43legacy_dyndbg feature);
57
58void b43legacy_debugfs_init(void);
59void b43legacy_debugfs_exit(void);
60void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev);
61void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev);
62void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
63 const struct b43legacy_txstatus *status);
64
65#else /* CONFIG_B43LEGACY_DEBUG*/
66
67static inline
68int b43legacy_debug(struct b43legacy_wldev *dev,
69 enum b43legacy_dyndbg feature)
70{
71 return 0;
72}
73
74static inline
75void b43legacy_debugfs_init(void) { }
76static inline
77void b43legacy_debugfs_exit(void) { }
78static inline
79void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) { }
80static inline
81void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) { }
82static inline
83void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
84 const struct b43legacy_txstatus *status)
85 { }
86
87#endif /* CONFIG_B43LEGACY_DEBUG*/
88
89#endif /* B43legacy_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
new file mode 100644
index 00000000000..8cb3dc4c474
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -0,0 +1,1565 @@
1/*
2
3 Broadcom B43legacy wireless driver
4
5 DMA ringbuffer and descriptor allocation/management
6
7 Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.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 "b43legacy.h"
31#include "dma.h"
32#include "main.h"
33#include "debugfs.h"
34#include "xmit.h"
35
36#include <linux/dma-mapping.h>
37#include <linux/pci.h>
38#include <linux/delay.h>
39#include <linux/skbuff.h>
40#include <net/dst.h>
41
42/* 32bit DMA ops. */
43static
44struct b43legacy_dmadesc_generic *op32_idx2desc(
45 struct b43legacy_dmaring *ring,
46 int slot,
47 struct b43legacy_dmadesc_meta **meta)
48{
49 struct b43legacy_dmadesc32 *desc;
50
51 *meta = &(ring->meta[slot]);
52 desc = ring->descbase;
53 desc = &(desc[slot]);
54
55 return (struct b43legacy_dmadesc_generic *)desc;
56}
57
58static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
59 struct b43legacy_dmadesc_generic *desc,
60 dma_addr_t dmaaddr, u16 bufsize,
61 int start, int end, int irq)
62{
63 struct b43legacy_dmadesc32 *descbase = ring->descbase;
64 int slot;
65 u32 ctl;
66 u32 addr;
67 u32 addrext;
68
69 slot = (int)(&(desc->dma32) - descbase);
70 B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
71
72 addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
73 addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK)
74 >> SSB_DMA_TRANSLATION_SHIFT;
75 addr |= ssb_dma_translation(ring->dev->dev);
76 ctl = (bufsize - ring->frameoffset)
77 & B43legacy_DMA32_DCTL_BYTECNT;
78 if (slot == ring->nr_slots - 1)
79 ctl |= B43legacy_DMA32_DCTL_DTABLEEND;
80 if (start)
81 ctl |= B43legacy_DMA32_DCTL_FRAMESTART;
82 if (end)
83 ctl |= B43legacy_DMA32_DCTL_FRAMEEND;
84 if (irq)
85 ctl |= B43legacy_DMA32_DCTL_IRQ;
86 ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT)
87 & B43legacy_DMA32_DCTL_ADDREXT_MASK;
88
89 desc->dma32.control = cpu_to_le32(ctl);
90 desc->dma32.address = cpu_to_le32(addr);
91}
92
93static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot)
94{
95 b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX,
96 (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
97}
98
99static void op32_tx_suspend(struct b43legacy_dmaring *ring)
100{
101 b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
102 b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
103 | B43legacy_DMA32_TXSUSPEND);
104}
105
106static void op32_tx_resume(struct b43legacy_dmaring *ring)
107{
108 b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
109 b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
110 & ~B43legacy_DMA32_TXSUSPEND);
111}
112
113static int op32_get_current_rxslot(struct b43legacy_dmaring *ring)
114{
115 u32 val;
116
117 val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS);
118 val &= B43legacy_DMA32_RXDPTR;
119
120 return (val / sizeof(struct b43legacy_dmadesc32));
121}
122
123static void op32_set_current_rxslot(struct b43legacy_dmaring *ring,
124 int slot)
125{
126 b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
127 (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
128}
129
130static const struct b43legacy_dma_ops dma32_ops = {
131 .idx2desc = op32_idx2desc,
132 .fill_descriptor = op32_fill_descriptor,
133 .poke_tx = op32_poke_tx,
134 .tx_suspend = op32_tx_suspend,
135 .tx_resume = op32_tx_resume,
136 .get_current_rxslot = op32_get_current_rxslot,
137 .set_current_rxslot = op32_set_current_rxslot,
138};
139
140/* 64bit DMA ops. */
141static
142struct b43legacy_dmadesc_generic *op64_idx2desc(
143 struct b43legacy_dmaring *ring,
144 int slot,
145 struct b43legacy_dmadesc_meta
146 **meta)
147{
148 struct b43legacy_dmadesc64 *desc;
149
150 *meta = &(ring->meta[slot]);
151 desc = ring->descbase;
152 desc = &(desc[slot]);
153
154 return (struct b43legacy_dmadesc_generic *)desc;
155}
156
157static void op64_fill_descriptor(struct b43legacy_dmaring *ring,
158 struct b43legacy_dmadesc_generic *desc,
159 dma_addr_t dmaaddr, u16 bufsize,
160 int start, int end, int irq)
161{
162 struct b43legacy_dmadesc64 *descbase = ring->descbase;
163 int slot;
164 u32 ctl0 = 0;
165 u32 ctl1 = 0;
166 u32 addrlo;
167 u32 addrhi;
168 u32 addrext;
169
170 slot = (int)(&(desc->dma64) - descbase);
171 B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
172
173 addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
174 addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
175 addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
176 >> SSB_DMA_TRANSLATION_SHIFT;
177 addrhi |= ssb_dma_translation(ring->dev->dev);
178 if (slot == ring->nr_slots - 1)
179 ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND;
180 if (start)
181 ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART;
182 if (end)
183 ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND;
184 if (irq)
185 ctl0 |= B43legacy_DMA64_DCTL0_IRQ;
186 ctl1 |= (bufsize - ring->frameoffset)
187 & B43legacy_DMA64_DCTL1_BYTECNT;
188 ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT)
189 & B43legacy_DMA64_DCTL1_ADDREXT_MASK;
190
191 desc->dma64.control0 = cpu_to_le32(ctl0);
192 desc->dma64.control1 = cpu_to_le32(ctl1);
193 desc->dma64.address_low = cpu_to_le32(addrlo);
194 desc->dma64.address_high = cpu_to_le32(addrhi);
195}
196
197static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot)
198{
199 b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX,
200 (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
201}
202
203static void op64_tx_suspend(struct b43legacy_dmaring *ring)
204{
205 b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
206 b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
207 | B43legacy_DMA64_TXSUSPEND);
208}
209
210static void op64_tx_resume(struct b43legacy_dmaring *ring)
211{
212 b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
213 b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
214 & ~B43legacy_DMA64_TXSUSPEND);
215}
216
217static int op64_get_current_rxslot(struct b43legacy_dmaring *ring)
218{
219 u32 val;
220
221 val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS);
222 val &= B43legacy_DMA64_RXSTATDPTR;
223
224 return (val / sizeof(struct b43legacy_dmadesc64));
225}
226
227static void op64_set_current_rxslot(struct b43legacy_dmaring *ring,
228 int slot)
229{
230 b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
231 (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
232}
233
234static const struct b43legacy_dma_ops dma64_ops = {
235 .idx2desc = op64_idx2desc,
236 .fill_descriptor = op64_fill_descriptor,
237 .poke_tx = op64_poke_tx,
238 .tx_suspend = op64_tx_suspend,
239 .tx_resume = op64_tx_resume,
240 .get_current_rxslot = op64_get_current_rxslot,
241 .set_current_rxslot = op64_set_current_rxslot,
242};
243
244
245static inline int free_slots(struct b43legacy_dmaring *ring)
246{
247 return (ring->nr_slots - ring->used_slots);
248}
249
250static inline int next_slot(struct b43legacy_dmaring *ring, int slot)
251{
252 B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1));
253 if (slot == ring->nr_slots - 1)
254 return 0;
255 return slot + 1;
256}
257
258static inline int prev_slot(struct b43legacy_dmaring *ring, int slot)
259{
260 B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1));
261 if (slot == 0)
262 return ring->nr_slots - 1;
263 return slot - 1;
264}
265
266#ifdef CONFIG_B43LEGACY_DEBUG
267static void update_max_used_slots(struct b43legacy_dmaring *ring,
268 int current_used_slots)
269{
270 if (current_used_slots <= ring->max_used_slots)
271 return;
272 ring->max_used_slots = current_used_slots;
273 if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE))
274 b43legacydbg(ring->dev->wl,
275 "max_used_slots increased to %d on %s ring %d\n",
276 ring->max_used_slots,
277 ring->tx ? "TX" : "RX",
278 ring->index);
279}
280#else
281static inline
282void update_max_used_slots(struct b43legacy_dmaring *ring,
283 int current_used_slots)
284{ }
285#endif /* DEBUG */
286
287/* Request a slot for usage. */
288static inline
289int request_slot(struct b43legacy_dmaring *ring)
290{
291 int slot;
292
293 B43legacy_WARN_ON(!ring->tx);
294 B43legacy_WARN_ON(ring->stopped);
295 B43legacy_WARN_ON(free_slots(ring) == 0);
296
297 slot = next_slot(ring, ring->current_slot);
298 ring->current_slot = slot;
299 ring->used_slots++;
300
301 update_max_used_slots(ring, ring->used_slots);
302
303 return slot;
304}
305
306/* Mac80211-queue to b43legacy-ring mapping */
307static struct b43legacy_dmaring *priority_to_txring(
308 struct b43legacy_wldev *dev,
309 int queue_priority)
310{
311 struct b43legacy_dmaring *ring;
312
313/*FIXME: For now we always run on TX-ring-1 */
314return dev->dma.tx_ring1;
315
316 /* 0 = highest priority */
317 switch (queue_priority) {
318 default:
319 B43legacy_WARN_ON(1);
320 /* fallthrough */
321 case 0:
322 ring = dev->dma.tx_ring3;
323 break;
324 case 1:
325 ring = dev->dma.tx_ring2;
326 break;
327 case 2:
328 ring = dev->dma.tx_ring1;
329 break;
330 case 3:
331 ring = dev->dma.tx_ring0;
332 break;
333 case 4:
334 ring = dev->dma.tx_ring4;
335 break;
336 case 5:
337 ring = dev->dma.tx_ring5;
338 break;
339 }
340
341 return ring;
342}
343
344/* Bcm4301-ring to mac80211-queue mapping */
345static inline int txring_to_priority(struct b43legacy_dmaring *ring)
346{
347 static const u8 idx_to_prio[] =
348 { 3, 2, 1, 0, 4, 5, };
349
350/*FIXME: have only one queue, for now */
351return 0;
352
353 return idx_to_prio[ring->index];
354}
355
356
357u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
358{
359 static const u16 map64[] = {
360 B43legacy_MMIO_DMA64_BASE0,
361 B43legacy_MMIO_DMA64_BASE1,
362 B43legacy_MMIO_DMA64_BASE2,
363 B43legacy_MMIO_DMA64_BASE3,
364 B43legacy_MMIO_DMA64_BASE4,
365 B43legacy_MMIO_DMA64_BASE5,
366 };
367 static const u16 map32[] = {
368 B43legacy_MMIO_DMA32_BASE0,
369 B43legacy_MMIO_DMA32_BASE1,
370 B43legacy_MMIO_DMA32_BASE2,
371 B43legacy_MMIO_DMA32_BASE3,
372 B43legacy_MMIO_DMA32_BASE4,
373 B43legacy_MMIO_DMA32_BASE5,
374 };
375
376 if (dma64bit) {
377 B43legacy_WARN_ON(!(controller_idx >= 0 &&
378 controller_idx < ARRAY_SIZE(map64)));
379 return map64[controller_idx];
380 }
381 B43legacy_WARN_ON(!(controller_idx >= 0 &&
382 controller_idx < ARRAY_SIZE(map32)));
383 return map32[controller_idx];
384}
385
386static inline
387dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
388 unsigned char *buf,
389 size_t len,
390 int tx)
391{
392 dma_addr_t dmaaddr;
393
394 if (tx)
395 dmaaddr = dma_map_single(ring->dev->dev->dev,
396 buf, len,
397 DMA_TO_DEVICE);
398 else
399 dmaaddr = dma_map_single(ring->dev->dev->dev,
400 buf, len,
401 DMA_FROM_DEVICE);
402
403 return dmaaddr;
404}
405
406static inline
407void unmap_descbuffer(struct b43legacy_dmaring *ring,
408 dma_addr_t addr,
409 size_t len,
410 int tx)
411{
412 if (tx)
413 dma_unmap_single(ring->dev->dev->dev,
414 addr, len,
415 DMA_TO_DEVICE);
416 else
417 dma_unmap_single(ring->dev->dev->dev,
418 addr, len,
419 DMA_FROM_DEVICE);
420}
421
422static inline
423void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
424 dma_addr_t addr,
425 size_t len)
426{
427 B43legacy_WARN_ON(ring->tx);
428
429 dma_sync_single_for_cpu(ring->dev->dev->dev,
430 addr, len, DMA_FROM_DEVICE);
431}
432
433static inline
434void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
435 dma_addr_t addr,
436 size_t len)
437{
438 B43legacy_WARN_ON(ring->tx);
439
440 dma_sync_single_for_device(ring->dev->dev->dev,
441 addr, len, DMA_FROM_DEVICE);
442}
443
444static inline
445void free_descriptor_buffer(struct b43legacy_dmaring *ring,
446 struct b43legacy_dmadesc_meta *meta,
447 int irq_context)
448{
449 if (meta->skb) {
450 if (irq_context)
451 dev_kfree_skb_irq(meta->skb);
452 else
453 dev_kfree_skb(meta->skb);
454 meta->skb = NULL;
455 }
456}
457
458static int alloc_ringmemory(struct b43legacy_dmaring *ring)
459{
460 struct device *dev = ring->dev->dev->dev;
461
462 ring->descbase = dma_alloc_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
463 &(ring->dmabase), GFP_KERNEL);
464 if (!ring->descbase) {
465 b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
466 " failed\n");
467 return -ENOMEM;
468 }
469 memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE);
470
471 return 0;
472}
473
474static void free_ringmemory(struct b43legacy_dmaring *ring)
475{
476 struct device *dev = ring->dev->dev->dev;
477
478 dma_free_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
479 ring->descbase, ring->dmabase);
480}
481
482/* Reset the RX DMA channel */
483int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
484 u16 mmio_base, int dma64)
485{
486 int i;
487 u32 value;
488 u16 offset;
489
490 might_sleep();
491
492 offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
493 b43legacy_write32(dev, mmio_base + offset, 0);
494 for (i = 0; i < 10; i++) {
495 offset = dma64 ? B43legacy_DMA64_RXSTATUS :
496 B43legacy_DMA32_RXSTATUS;
497 value = b43legacy_read32(dev, mmio_base + offset);
498 if (dma64) {
499 value &= B43legacy_DMA64_RXSTAT;
500 if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
501 i = -1;
502 break;
503 }
504 } else {
505 value &= B43legacy_DMA32_RXSTATE;
506 if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
507 i = -1;
508 break;
509 }
510 }
511 msleep(1);
512 }
513 if (i != -1) {
514 b43legacyerr(dev->wl, "DMA RX reset timed out\n");
515 return -ENODEV;
516 }
517
518 return 0;
519}
520
521/* Reset the RX DMA channel */
522int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
523 u16 mmio_base, int dma64)
524{
525 int i;
526 u32 value;
527 u16 offset;
528
529 might_sleep();
530
531 for (i = 0; i < 10; i++) {
532 offset = dma64 ? B43legacy_DMA64_TXSTATUS :
533 B43legacy_DMA32_TXSTATUS;
534 value = b43legacy_read32(dev, mmio_base + offset);
535 if (dma64) {
536 value &= B43legacy_DMA64_TXSTAT;
537 if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
538 value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
539 value == B43legacy_DMA64_TXSTAT_STOPPED)
540 break;
541 } else {
542 value &= B43legacy_DMA32_TXSTATE;
543 if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
544 value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
545 value == B43legacy_DMA32_TXSTAT_STOPPED)
546 break;
547 }
548 msleep(1);
549 }
550 offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL;
551 b43legacy_write32(dev, mmio_base + offset, 0);
552 for (i = 0; i < 10; i++) {
553 offset = dma64 ? B43legacy_DMA64_TXSTATUS :
554 B43legacy_DMA32_TXSTATUS;
555 value = b43legacy_read32(dev, mmio_base + offset);
556 if (dma64) {
557 value &= B43legacy_DMA64_TXSTAT;
558 if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
559 i = -1;
560 break;
561 }
562 } else {
563 value &= B43legacy_DMA32_TXSTATE;
564 if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
565 i = -1;
566 break;
567 }
568 }
569 msleep(1);
570 }
571 if (i != -1) {
572 b43legacyerr(dev->wl, "DMA TX reset timed out\n");
573 return -ENODEV;
574 }
575 /* ensure the reset is completed. */
576 msleep(1);
577
578 return 0;
579}
580
581static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
582 struct b43legacy_dmadesc_generic *desc,
583 struct b43legacy_dmadesc_meta *meta,
584 gfp_t gfp_flags)
585{
586 struct b43legacy_rxhdr_fw3 *rxhdr;
587 struct b43legacy_hwtxstatus *txstat;
588 dma_addr_t dmaaddr;
589 struct sk_buff *skb;
590
591 B43legacy_WARN_ON(ring->tx);
592
593 skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
594 if (unlikely(!skb))
595 return -ENOMEM;
596 dmaaddr = map_descbuffer(ring, skb->data,
597 ring->rx_buffersize, 0);
598 if (dma_mapping_error(dmaaddr)) {
599 /* ugh. try to realloc in zone_dma */
600 gfp_flags |= GFP_DMA;
601
602 dev_kfree_skb_any(skb);
603
604 skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
605 if (unlikely(!skb))
606 return -ENOMEM;
607 dmaaddr = map_descbuffer(ring, skb->data,
608 ring->rx_buffersize, 0);
609 }
610
611 if (dma_mapping_error(dmaaddr)) {
612 dev_kfree_skb_any(skb);
613 return -EIO;
614 }
615
616 meta->skb = skb;
617 meta->dmaaddr = dmaaddr;
618 ring->ops->fill_descriptor(ring, desc, dmaaddr,
619 ring->rx_buffersize, 0, 0, 0);
620
621 rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data);
622 rxhdr->frame_len = 0;
623 txstat = (struct b43legacy_hwtxstatus *)(skb->data);
624 txstat->cookie = 0;
625
626 return 0;
627}
628
629/* Allocate the initial descbuffers.
630 * This is used for an RX ring only.
631 */
632static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring)
633{
634 int i;
635 int err = -ENOMEM;
636 struct b43legacy_dmadesc_generic *desc;
637 struct b43legacy_dmadesc_meta *meta;
638
639 for (i = 0; i < ring->nr_slots; i++) {
640 desc = ring->ops->idx2desc(ring, i, &meta);
641
642 err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
643 if (err) {
644 b43legacyerr(ring->dev->wl,
645 "Failed to allocate initial descbuffers\n");
646 goto err_unwind;
647 }
648 }
649 mb(); /* all descbuffer setup before next line */
650 ring->used_slots = ring->nr_slots;
651 err = 0;
652out:
653 return err;
654
655err_unwind:
656 for (i--; i >= 0; i--) {
657 desc = ring->ops->idx2desc(ring, i, &meta);
658
659 unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
660 dev_kfree_skb(meta->skb);
661 }
662 goto out;
663}
664
665/* Do initial setup of the DMA controller.
666 * Reset the controller, write the ring busaddress
667 * and switch the "enable" bit on.
668 */
669static int dmacontroller_setup(struct b43legacy_dmaring *ring)
670{
671 int err = 0;
672 u32 value;
673 u32 addrext;
674 u32 trans = ssb_dma_translation(ring->dev->dev);
675
676 if (ring->tx) {
677 if (ring->dma64) {
678 u64 ringbase = (u64)(ring->dmabase);
679
680 addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
681 >> SSB_DMA_TRANSLATION_SHIFT;
682 value = B43legacy_DMA64_TXENABLE;
683 value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT)
684 & B43legacy_DMA64_TXADDREXT_MASK;
685 b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
686 value);
687 b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO,
688 (ringbase & 0xFFFFFFFF));
689 b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI,
690 ((ringbase >> 32)
691 & ~SSB_DMA_TRANSLATION_MASK)
692 | trans);
693 } else {
694 u32 ringbase = (u32)(ring->dmabase);
695
696 addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
697 >> SSB_DMA_TRANSLATION_SHIFT;
698 value = B43legacy_DMA32_TXENABLE;
699 value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
700 & B43legacy_DMA32_TXADDREXT_MASK;
701 b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
702 value);
703 b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
704 (ringbase &
705 ~SSB_DMA_TRANSLATION_MASK)
706 | trans);
707 }
708 } else {
709 err = alloc_initial_descbuffers(ring);
710 if (err)
711 goto out;
712 if (ring->dma64) {
713 u64 ringbase = (u64)(ring->dmabase);
714
715 addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
716 >> SSB_DMA_TRANSLATION_SHIFT;
717 value = (ring->frameoffset <<
718 B43legacy_DMA64_RXFROFF_SHIFT);
719 value |= B43legacy_DMA64_RXENABLE;
720 value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT)
721 & B43legacy_DMA64_RXADDREXT_MASK;
722 b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL,
723 value);
724 b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO,
725 (ringbase & 0xFFFFFFFF));
726 b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI,
727 ((ringbase >> 32) &
728 ~SSB_DMA_TRANSLATION_MASK) |
729 trans);
730 b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
731 200);
732 } else {
733 u32 ringbase = (u32)(ring->dmabase);
734
735 addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
736 >> SSB_DMA_TRANSLATION_SHIFT;
737 value = (ring->frameoffset <<
738 B43legacy_DMA32_RXFROFF_SHIFT);
739 value |= B43legacy_DMA32_RXENABLE;
740 value |= (addrext <<
741 B43legacy_DMA32_RXADDREXT_SHIFT)
742 & B43legacy_DMA32_RXADDREXT_MASK;
743 b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL,
744 value);
745 b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
746 (ringbase &
747 ~SSB_DMA_TRANSLATION_MASK)
748 | trans);
749 b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
750 200);
751 }
752 }
753
754out:
755 return err;
756}
757
758/* Shutdown the DMA controller. */
759static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
760{
761 if (ring->tx) {
762 b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
763 ring->dma64);
764 if (ring->dma64) {
765 b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
766 b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
767 } else
768 b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
769 } else {
770 b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
771 ring->dma64);
772 if (ring->dma64) {
773 b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
774 b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
775 } else
776 b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
777 }
778}
779
780static void free_all_descbuffers(struct b43legacy_dmaring *ring)
781{
782 struct b43legacy_dmadesc_generic *desc;
783 struct b43legacy_dmadesc_meta *meta;
784 int i;
785
786 if (!ring->used_slots)
787 return;
788 for (i = 0; i < ring->nr_slots; i++) {
789 desc = ring->ops->idx2desc(ring, i, &meta);
790
791 if (!meta->skb) {
792 B43legacy_WARN_ON(!ring->tx);
793 continue;
794 }
795 if (ring->tx)
796 unmap_descbuffer(ring, meta->dmaaddr,
797 meta->skb->len, 1);
798 else
799 unmap_descbuffer(ring, meta->dmaaddr,
800 ring->rx_buffersize, 0);
801 free_descriptor_buffer(ring, meta, 0);
802 }
803}
804
805static u64 supported_dma_mask(struct b43legacy_wldev *dev)
806{
807 u32 tmp;
808 u16 mmio_base;
809
810 tmp = b43legacy_read32(dev, SSB_TMSHIGH);
811 if (tmp & SSB_TMSHIGH_DMA64)
812 return DMA_64BIT_MASK;
813 mmio_base = b43legacy_dmacontroller_base(0, 0);
814 b43legacy_write32(dev,
815 mmio_base + B43legacy_DMA32_TXCTL,
816 B43legacy_DMA32_TXADDREXT_MASK);
817 tmp = b43legacy_read32(dev, mmio_base +
818 B43legacy_DMA32_TXCTL);
819 if (tmp & B43legacy_DMA32_TXADDREXT_MASK)
820 return DMA_32BIT_MASK;
821
822 return DMA_30BIT_MASK;
823}
824
825/* Main initialization function. */
826static
827struct b43legacy_dmaring *b43legacy_setup_dmaring(
828 struct b43legacy_wldev *dev,
829 int controller_index,
830 int for_tx,
831 int dma64)
832{
833 struct b43legacy_dmaring *ring;
834 int err;
835 int nr_slots;
836 dma_addr_t dma_test;
837
838 ring = kzalloc(sizeof(*ring), GFP_KERNEL);
839 if (!ring)
840 goto out;
841
842 nr_slots = B43legacy_RXRING_SLOTS;
843 if (for_tx)
844 nr_slots = B43legacy_TXRING_SLOTS;
845
846 ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta),
847 GFP_KERNEL);
848 if (!ring->meta)
849 goto err_kfree_ring;
850 if (for_tx) {
851 ring->txhdr_cache = kcalloc(nr_slots,
852 sizeof(struct b43legacy_txhdr_fw3),
853 GFP_KERNEL);
854 if (!ring->txhdr_cache)
855 goto err_kfree_meta;
856
857 /* test for ability to dma to txhdr_cache */
858 dma_test = dma_map_single(dev->dev->dev,
859 ring->txhdr_cache,
860 sizeof(struct b43legacy_txhdr_fw3),
861 DMA_TO_DEVICE);
862
863 if (dma_mapping_error(dma_test)) {
864 /* ugh realloc */
865 kfree(ring->txhdr_cache);
866 ring->txhdr_cache = kcalloc(nr_slots,
867 sizeof(struct b43legacy_txhdr_fw3),
868 GFP_KERNEL | GFP_DMA);
869 if (!ring->txhdr_cache)
870 goto err_kfree_meta;
871
872 dma_test = dma_map_single(dev->dev->dev,
873 ring->txhdr_cache,
874 sizeof(struct b43legacy_txhdr_fw3),
875 DMA_TO_DEVICE);
876
877 if (dma_mapping_error(dma_test))
878 goto err_kfree_txhdr_cache;
879 }
880
881 dma_unmap_single(dev->dev->dev,
882 dma_test, sizeof(struct b43legacy_txhdr_fw3),
883 DMA_TO_DEVICE);
884 }
885
886 ring->dev = dev;
887 ring->nr_slots = nr_slots;
888 ring->mmio_base = b43legacy_dmacontroller_base(dma64,
889 controller_index);
890 ring->index = controller_index;
891 ring->dma64 = !!dma64;
892 if (dma64)
893 ring->ops = &dma64_ops;
894 else
895 ring->ops = &dma32_ops;
896 if (for_tx) {
897 ring->tx = 1;
898 ring->current_slot = -1;
899 } else {
900 if (ring->index == 0) {
901 ring->rx_buffersize = B43legacy_DMA0_RX_BUFFERSIZE;
902 ring->frameoffset = B43legacy_DMA0_RX_FRAMEOFFSET;
903 } else if (ring->index == 3) {
904 ring->rx_buffersize = B43legacy_DMA3_RX_BUFFERSIZE;
905 ring->frameoffset = B43legacy_DMA3_RX_FRAMEOFFSET;
906 } else
907 B43legacy_WARN_ON(1);
908 }
909 spin_lock_init(&ring->lock);
910#ifdef CONFIG_B43LEGACY_DEBUG
911 ring->last_injected_overflow = jiffies;
912#endif
913
914 err = alloc_ringmemory(ring);
915 if (err)
916 goto err_kfree_txhdr_cache;
917 err = dmacontroller_setup(ring);
918 if (err)
919 goto err_free_ringmemory;
920
921out:
922 return ring;
923
924err_free_ringmemory:
925 free_ringmemory(ring);
926err_kfree_txhdr_cache:
927 kfree(ring->txhdr_cache);
928err_kfree_meta:
929 kfree(ring->meta);
930err_kfree_ring:
931 kfree(ring);
932 ring = NULL;
933 goto out;
934}
935
936/* Main cleanup function. */
937static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring)
938{
939 if (!ring)
940 return;
941
942 b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:"
943 " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base,
944 (ring->tx) ? "TX" : "RX",
945 ring->max_used_slots, ring->nr_slots);
946 /* Device IRQs are disabled prior entering this function,
947 * so no need to take care of concurrency with rx handler stuff.
948 */
949 dmacontroller_cleanup(ring);
950 free_all_descbuffers(ring);
951 free_ringmemory(ring);
952
953 kfree(ring->txhdr_cache);
954 kfree(ring->meta);
955 kfree(ring);
956}
957
958void b43legacy_dma_free(struct b43legacy_wldev *dev)
959{
960 struct b43legacy_dma *dma;
961
962 if (b43legacy_using_pio(dev))
963 return;
964 dma = &dev->dma;
965
966 b43legacy_destroy_dmaring(dma->rx_ring3);
967 dma->rx_ring3 = NULL;
968 b43legacy_destroy_dmaring(dma->rx_ring0);
969 dma->rx_ring0 = NULL;
970
971 b43legacy_destroy_dmaring(dma->tx_ring5);
972 dma->tx_ring5 = NULL;
973 b43legacy_destroy_dmaring(dma->tx_ring4);
974 dma->tx_ring4 = NULL;
975 b43legacy_destroy_dmaring(dma->tx_ring3);
976 dma->tx_ring3 = NULL;
977 b43legacy_destroy_dmaring(dma->tx_ring2);
978 dma->tx_ring2 = NULL;
979 b43legacy_destroy_dmaring(dma->tx_ring1);
980 dma->tx_ring1 = NULL;
981 b43legacy_destroy_dmaring(dma->tx_ring0);
982 dma->tx_ring0 = NULL;
983}
984
985int b43legacy_dma_init(struct b43legacy_wldev *dev)
986{
987 struct b43legacy_dma *dma = &dev->dma;
988 struct b43legacy_dmaring *ring;
989 int err;
990 u64 dmamask;
991 int dma64 = 0;
992
993 dmamask = supported_dma_mask(dev);
994 if (dmamask == DMA_64BIT_MASK)
995 dma64 = 1;
996
997 err = ssb_dma_set_mask(dev->dev, dmamask);
998 if (err) {
999#ifdef BCM43XX_PIO
1000 b43legacywarn(dev->wl, "DMA for this device not supported. "
1001 "Falling back to PIO\n");
1002 dev->__using_pio = 1;
1003 return -EAGAIN;
1004#else
1005 b43legacyerr(dev->wl, "DMA for this device not supported and "
1006 "no PIO support compiled in\n");
1007 return -EOPNOTSUPP;
1008#endif
1009 }
1010
1011 err = -ENOMEM;
1012 /* setup TX DMA channels. */
1013 ring = b43legacy_setup_dmaring(dev, 0, 1, dma64);
1014 if (!ring)
1015 goto out;
1016 dma->tx_ring0 = ring;
1017
1018 ring = b43legacy_setup_dmaring(dev, 1, 1, dma64);
1019 if (!ring)
1020 goto err_destroy_tx0;
1021 dma->tx_ring1 = ring;
1022
1023 ring = b43legacy_setup_dmaring(dev, 2, 1, dma64);
1024 if (!ring)
1025 goto err_destroy_tx1;
1026 dma->tx_ring2 = ring;
1027
1028 ring = b43legacy_setup_dmaring(dev, 3, 1, dma64);
1029 if (!ring)
1030 goto err_destroy_tx2;
1031 dma->tx_ring3 = ring;
1032
1033 ring = b43legacy_setup_dmaring(dev, 4, 1, dma64);
1034 if (!ring)
1035 goto err_destroy_tx3;
1036 dma->tx_ring4 = ring;
1037
1038 ring = b43legacy_setup_dmaring(dev, 5, 1, dma64);
1039 if (!ring)
1040 goto err_destroy_tx4;
1041 dma->tx_ring5 = ring;
1042
1043 /* setup RX DMA channels. */
1044 ring = b43legacy_setup_dmaring(dev, 0, 0, dma64);
1045 if (!ring)
1046 goto err_destroy_tx5;
1047 dma->rx_ring0 = ring;
1048
1049 if (dev->dev->id.revision < 5) {
1050 ring = b43legacy_setup_dmaring(dev, 3, 0, dma64);
1051 if (!ring)
1052 goto err_destroy_rx0;
1053 dma->rx_ring3 = ring;
1054 }
1055
1056 b43legacydbg(dev->wl, "%d-bit DMA initialized\n",
1057 (dmamask == DMA_64BIT_MASK) ? 64 :
1058 (dmamask == DMA_32BIT_MASK) ? 32 : 30);
1059 err = 0;
1060out:
1061 return err;
1062
1063err_destroy_rx0:
1064 b43legacy_destroy_dmaring(dma->rx_ring0);
1065 dma->rx_ring0 = NULL;
1066err_destroy_tx5:
1067 b43legacy_destroy_dmaring(dma->tx_ring5);
1068 dma->tx_ring5 = NULL;
1069err_destroy_tx4:
1070 b43legacy_destroy_dmaring(dma->tx_ring4);
1071 dma->tx_ring4 = NULL;
1072err_destroy_tx3:
1073 b43legacy_destroy_dmaring(dma->tx_ring3);
1074 dma->tx_ring3 = NULL;
1075err_destroy_tx2:
1076 b43legacy_destroy_dmaring(dma->tx_ring2);
1077 dma->tx_ring2 = NULL;
1078err_destroy_tx1:
1079 b43legacy_destroy_dmaring(dma->tx_ring1);
1080 dma->tx_ring1 = NULL;
1081err_destroy_tx0:
1082 b43legacy_destroy_dmaring(dma->tx_ring0);
1083 dma->tx_ring0 = NULL;
1084 goto out;
1085}
1086
1087/* Generate a cookie for the TX header. */
1088static u16 generate_cookie(struct b43legacy_dmaring *ring,
1089 int slot)
1090{
1091 u16 cookie = 0x1000;
1092
1093 /* Use the upper 4 bits of the cookie as
1094 * DMA controller ID and store the slot number
1095 * in the lower 12 bits.
1096 * Note that the cookie must never be 0, as this
1097 * is a special value used in RX path.
1098 */
1099 switch (ring->index) {
1100 case 0:
1101 cookie = 0xA000;
1102 break;
1103 case 1:
1104 cookie = 0xB000;
1105 break;
1106 case 2:
1107 cookie = 0xC000;
1108 break;
1109 case 3:
1110 cookie = 0xD000;
1111 break;
1112 case 4:
1113 cookie = 0xE000;
1114 break;
1115 case 5:
1116 cookie = 0xF000;
1117 break;
1118 }
1119 B43legacy_WARN_ON(!(((u16)slot & 0xF000) == 0x0000));
1120 cookie |= (u16)slot;
1121
1122 return cookie;
1123}
1124
1125/* Inspect a cookie and find out to which controller/slot it belongs. */
1126static
1127struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev,
1128 u16 cookie, int *slot)
1129{
1130 struct b43legacy_dma *dma = &dev->dma;
1131 struct b43legacy_dmaring *ring = NULL;
1132
1133 switch (cookie & 0xF000) {
1134 case 0xA000:
1135 ring = dma->tx_ring0;
1136 break;
1137 case 0xB000:
1138 ring = dma->tx_ring1;
1139 break;
1140 case 0xC000:
1141 ring = dma->tx_ring2;
1142 break;
1143 case 0xD000:
1144 ring = dma->tx_ring3;
1145 break;
1146 case 0xE000:
1147 ring = dma->tx_ring4;
1148 break;
1149 case 0xF000:
1150 ring = dma->tx_ring5;
1151 break;
1152 default:
1153 B43legacy_WARN_ON(1);
1154 }
1155 *slot = (cookie & 0x0FFF);
1156 B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
1157
1158 return ring;
1159}
1160
1161static int dma_tx_fragment(struct b43legacy_dmaring *ring,
1162 struct sk_buff *skb,
1163 struct ieee80211_tx_control *ctl)
1164{
1165 const struct b43legacy_dma_ops *ops = ring->ops;
1166 u8 *header;
1167 int slot;
1168 int err;
1169 struct b43legacy_dmadesc_generic *desc;
1170 struct b43legacy_dmadesc_meta *meta;
1171 struct b43legacy_dmadesc_meta *meta_hdr;
1172 struct sk_buff *bounce_skb;
1173
1174#define SLOTS_PER_PACKET 2
1175 B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
1176
1177 /* Get a slot for the header. */
1178 slot = request_slot(ring);
1179 desc = ops->idx2desc(ring, slot, &meta_hdr);
1180 memset(meta_hdr, 0, sizeof(*meta_hdr));
1181
1182 header = &(ring->txhdr_cache[slot * sizeof(
1183 struct b43legacy_txhdr_fw3)]);
1184 b43legacy_generate_txhdr(ring->dev, header,
1185 skb->data, skb->len, ctl,
1186 generate_cookie(ring, slot));
1187
1188 meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
1189 sizeof(struct b43legacy_txhdr_fw3), 1);
1190 if (dma_mapping_error(meta_hdr->dmaaddr))
1191 return -EIO;
1192 ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
1193 sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
1194
1195 /* Get a slot for the payload. */
1196 slot = request_slot(ring);
1197 desc = ops->idx2desc(ring, slot, &meta);
1198 memset(meta, 0, sizeof(*meta));
1199
1200 memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
1201 meta->skb = skb;
1202 meta->is_last_fragment = 1;
1203
1204 meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
1205 /* create a bounce buffer in zone_dma on mapping failure. */
1206 if (dma_mapping_error(meta->dmaaddr)) {
1207 bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
1208 if (!bounce_skb) {
1209 err = -ENOMEM;
1210 goto out_unmap_hdr;
1211 }
1212
1213 memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
1214 dev_kfree_skb_any(skb);
1215 skb = bounce_skb;
1216 meta->skb = skb;
1217 meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
1218 if (dma_mapping_error(meta->dmaaddr)) {
1219 err = -EIO;
1220 goto out_free_bounce;
1221 }
1222 }
1223
1224 ops->fill_descriptor(ring, desc, meta->dmaaddr,
1225 skb->len, 0, 1, 1);
1226
1227 wmb(); /* previous stuff MUST be done */
1228 /* Now transfer the whole frame. */
1229 ops->poke_tx(ring, next_slot(ring, slot));
1230 return 0;
1231
1232out_free_bounce:
1233 dev_kfree_skb_any(skb);
1234out_unmap_hdr:
1235 unmap_descbuffer(ring, meta_hdr->dmaaddr,
1236 sizeof(struct b43legacy_txhdr_fw3), 1);
1237 return err;
1238}
1239
1240static inline
1241int should_inject_overflow(struct b43legacy_dmaring *ring)
1242{
1243#ifdef CONFIG_B43LEGACY_DEBUG
1244 if (unlikely(b43legacy_debug(ring->dev,
1245 B43legacy_DBG_DMAOVERFLOW))) {
1246 /* Check if we should inject another ringbuffer overflow
1247 * to test handling of this situation in the stack. */
1248 unsigned long next_overflow;
1249
1250 next_overflow = ring->last_injected_overflow + HZ;
1251 if (time_after(jiffies, next_overflow)) {
1252 ring->last_injected_overflow = jiffies;
1253 b43legacydbg(ring->dev->wl,
1254 "Injecting TX ring overflow on "
1255 "DMA controller %d\n", ring->index);
1256 return 1;
1257 }
1258 }
1259#endif /* CONFIG_B43LEGACY_DEBUG */
1260 return 0;
1261}
1262
1263int b43legacy_dma_tx(struct b43legacy_wldev *dev,
1264 struct sk_buff *skb,
1265 struct ieee80211_tx_control *ctl)
1266{
1267 struct b43legacy_dmaring *ring;
1268 int err = 0;
1269 unsigned long flags;
1270
1271 ring = priority_to_txring(dev, ctl->queue);
1272 spin_lock_irqsave(&ring->lock, flags);
1273 B43legacy_WARN_ON(!ring->tx);
1274 if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
1275 b43legacywarn(dev->wl, "DMA queue overflow\n");
1276 err = -ENOSPC;
1277 goto out_unlock;
1278 }
1279 /* Check if the queue was stopped in mac80211,
1280 * but we got called nevertheless.
1281 * That would be a mac80211 bug. */
1282 B43legacy_BUG_ON(ring->stopped);
1283
1284 err = dma_tx_fragment(ring, skb, ctl);
1285 if (unlikely(err)) {
1286 b43legacyerr(dev->wl, "DMA tx mapping failure\n");
1287 goto out_unlock;
1288 }
1289 ring->nr_tx_packets++;
1290 if ((free_slots(ring) < SLOTS_PER_PACKET) ||
1291 should_inject_overflow(ring)) {
1292 /* This TX ring is full. */
1293 ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
1294 ring->stopped = 1;
1295 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
1296 b43legacydbg(dev->wl, "Stopped TX ring %d\n",
1297 ring->index);
1298 }
1299out_unlock:
1300 spin_unlock_irqrestore(&ring->lock, flags);
1301
1302 return err;
1303}
1304
1305void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
1306 const struct b43legacy_txstatus *status)
1307{
1308 const struct b43legacy_dma_ops *ops;
1309 struct b43legacy_dmaring *ring;
1310 struct b43legacy_dmadesc_generic *desc;
1311 struct b43legacy_dmadesc_meta *meta;
1312 int slot;
1313
1314 ring = parse_cookie(dev, status->cookie, &slot);
1315 if (unlikely(!ring))
1316 return;
1317 B43legacy_WARN_ON(!irqs_disabled());
1318 spin_lock(&ring->lock);
1319
1320 B43legacy_WARN_ON(!ring->tx);
1321 ops = ring->ops;
1322 while (1) {
1323 B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
1324 desc = ops->idx2desc(ring, slot, &meta);
1325
1326 if (meta->skb)
1327 unmap_descbuffer(ring, meta->dmaaddr,
1328 meta->skb->len, 1);
1329 else
1330 unmap_descbuffer(ring, meta->dmaaddr,
1331 sizeof(struct b43legacy_txhdr_fw3),
1332 1);
1333
1334 if (meta->is_last_fragment) {
1335 B43legacy_WARN_ON(!meta->skb);
1336 /* Call back to inform the ieee80211 subsystem about the
1337 * status of the transmission.
1338 * Some fields of txstat are already filled in dma_tx().
1339 */
1340 if (status->acked) {
1341 meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
1342 } else {
1343 if (!(meta->txstat.control.flags
1344 & IEEE80211_TXCTL_NO_ACK))
1345 meta->txstat.excessive_retries = 1;
1346 }
1347 if (status->frame_count == 0) {
1348 /* The frame was not transmitted at all. */
1349 meta->txstat.retry_count = 0;
1350 } else
1351 meta->txstat.retry_count = status->frame_count
1352 - 1;
1353 ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
1354 &(meta->txstat));
1355 /* skb is freed by ieee80211_tx_status_irqsafe() */
1356 meta->skb = NULL;
1357 } else {
1358 /* No need to call free_descriptor_buffer here, as
1359 * this is only the txhdr, which is not allocated.
1360 */
1361 B43legacy_WARN_ON(meta->skb != NULL);
1362 }
1363
1364 /* Everything unmapped and free'd. So it's not used anymore. */
1365 ring->used_slots--;
1366
1367 if (meta->is_last_fragment)
1368 break;
1369 slot = next_slot(ring, slot);
1370 }
1371 dev->stats.last_tx = jiffies;
1372 if (ring->stopped) {
1373 B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
1374 ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
1375 ring->stopped = 0;
1376 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
1377 b43legacydbg(dev->wl, "Woke up TX ring %d\n",
1378 ring->index);
1379 }
1380
1381 spin_unlock(&ring->lock);
1382}
1383
1384void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
1385 struct ieee80211_tx_queue_stats *stats)
1386{
1387 const int nr_queues = dev->wl->hw->queues;
1388 struct b43legacy_dmaring *ring;
1389 struct ieee80211_tx_queue_stats_data *data;
1390 unsigned long flags;
1391 int i;
1392
1393 for (i = 0; i < nr_queues; i++) {
1394 data = &(stats->data[i]);
1395 ring = priority_to_txring(dev, i);
1396
1397 spin_lock_irqsave(&ring->lock, flags);
1398 data->len = ring->used_slots / SLOTS_PER_PACKET;
1399 data->limit = ring->nr_slots / SLOTS_PER_PACKET;
1400 data->count = ring->nr_tx_packets;
1401 spin_unlock_irqrestore(&ring->lock, flags);
1402 }
1403}
1404
1405static void dma_rx(struct b43legacy_dmaring *ring,
1406 int *slot)
1407{
1408 const struct b43legacy_dma_ops *ops = ring->ops;
1409 struct b43legacy_dmadesc_generic *desc;
1410 struct b43legacy_dmadesc_meta *meta;
1411 struct b43legacy_rxhdr_fw3 *rxhdr;
1412 struct sk_buff *skb;
1413 u16 len;
1414 int err;
1415 dma_addr_t dmaaddr;
1416
1417 desc = ops->idx2desc(ring, *slot, &meta);
1418
1419 sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
1420 skb = meta->skb;
1421
1422 if (ring->index == 3) {
1423 /* We received an xmit status. */
1424 struct b43legacy_hwtxstatus *hw =
1425 (struct b43legacy_hwtxstatus *)skb->data;
1426 int i = 0;
1427
1428 while (hw->cookie == 0) {
1429 if (i > 100)
1430 break;
1431 i++;
1432 udelay(2);
1433 barrier();
1434 }
1435 b43legacy_handle_hwtxstatus(ring->dev, hw);
1436 /* recycle the descriptor buffer. */
1437 sync_descbuffer_for_device(ring, meta->dmaaddr,
1438 ring->rx_buffersize);
1439
1440 return;
1441 }
1442 rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data;
1443 len = le16_to_cpu(rxhdr->frame_len);
1444 if (len == 0) {
1445 int i = 0;
1446
1447 do {
1448 udelay(2);
1449 barrier();
1450 len = le16_to_cpu(rxhdr->frame_len);
1451 } while (len == 0 && i++ < 5);
1452 if (unlikely(len == 0)) {
1453 /* recycle the descriptor buffer. */
1454 sync_descbuffer_for_device(ring, meta->dmaaddr,
1455 ring->rx_buffersize);
1456 goto drop;
1457 }
1458 }
1459 if (unlikely(len > ring->rx_buffersize)) {
1460 /* The data did not fit into one descriptor buffer
1461 * and is split over multiple buffers.
1462 * This should never happen, as we try to allocate buffers
1463 * big enough. So simply ignore this packet.
1464 */
1465 int cnt = 0;
1466 s32 tmp = len;
1467
1468 while (1) {
1469 desc = ops->idx2desc(ring, *slot, &meta);
1470 /* recycle the descriptor buffer. */
1471 sync_descbuffer_for_device(ring, meta->dmaaddr,
1472 ring->rx_buffersize);
1473 *slot = next_slot(ring, *slot);
1474 cnt++;
1475 tmp -= ring->rx_buffersize;
1476 if (tmp <= 0)
1477 break;
1478 }
1479 b43legacyerr(ring->dev->wl, "DMA RX buffer too small "
1480 "(len: %u, buffer: %u, nr-dropped: %d)\n",
1481 len, ring->rx_buffersize, cnt);
1482 goto drop;
1483 }
1484
1485 dmaaddr = meta->dmaaddr;
1486 err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
1487 if (unlikely(err)) {
1488 b43legacydbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer()"
1489 " failed\n");
1490 sync_descbuffer_for_device(ring, dmaaddr,
1491 ring->rx_buffersize);
1492 goto drop;
1493 }
1494
1495 unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
1496 skb_put(skb, len + ring->frameoffset);
1497 skb_pull(skb, ring->frameoffset);
1498
1499 b43legacy_rx(ring->dev, skb, rxhdr);
1500drop:
1501 return;
1502}
1503
1504void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
1505{
1506 const struct b43legacy_dma_ops *ops = ring->ops;
1507 int slot;
1508 int current_slot;
1509 int used_slots = 0;
1510
1511 B43legacy_WARN_ON(ring->tx);
1512 current_slot = ops->get_current_rxslot(ring);
1513 B43legacy_WARN_ON(!(current_slot >= 0 && current_slot <
1514 ring->nr_slots));
1515
1516 slot = ring->current_slot;
1517 for (; slot != current_slot; slot = next_slot(ring, slot)) {
1518 dma_rx(ring, &slot);
1519 update_max_used_slots(ring, ++used_slots);
1520 }
1521 ops->set_current_rxslot(ring, slot);
1522 ring->current_slot = slot;
1523}
1524
1525static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
1526{
1527 unsigned long flags;
1528
1529 spin_lock_irqsave(&ring->lock, flags);
1530 B43legacy_WARN_ON(!ring->tx);
1531 ring->ops->tx_suspend(ring);
1532 spin_unlock_irqrestore(&ring->lock, flags);
1533}
1534
1535static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
1536{
1537 unsigned long flags;
1538
1539 spin_lock_irqsave(&ring->lock, flags);
1540 B43legacy_WARN_ON(!ring->tx);
1541 ring->ops->tx_resume(ring);
1542 spin_unlock_irqrestore(&ring->lock, flags);
1543}
1544
1545void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
1546{
1547 b43legacy_power_saving_ctl_bits(dev, -1, 1);
1548 b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring0);
1549 b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring1);
1550 b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring2);
1551 b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring3);
1552 b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring4);
1553 b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring5);
1554}
1555
1556void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
1557{
1558 b43legacy_dma_tx_resume_ring(dev->dma.tx_ring5);
1559 b43legacy_dma_tx_resume_ring(dev->dma.tx_ring4);
1560 b43legacy_dma_tx_resume_ring(dev->dma.tx_ring3);
1561 b43legacy_dma_tx_resume_ring(dev->dma.tx_ring2);
1562 b43legacy_dma_tx_resume_ring(dev->dma.tx_ring1);
1563 b43legacy_dma_tx_resume_ring(dev->dma.tx_ring0);
1564 b43legacy_power_saving_ctl_bits(dev, -1, -1);
1565}
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
new file mode 100644
index 00000000000..26f6ab08de7
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -0,0 +1,367 @@
1#ifndef B43legacy_DMA_H_
2#define B43legacy_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#include "b43legacy.h"
11
12
13/* DMA-Interrupt reasons. */
14#define B43legacy_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
15 | (1 << 14) | (1 << 15))
16#define B43legacy_DMAIRQ_NONFATALMASK (1 << 13)
17#define B43legacy_DMAIRQ_RX_DONE (1 << 16)
18
19
20/*** 32-bit DMA Engine. ***/
21
22/* 32-bit DMA controller registers. */
23#define B43legacy_DMA32_TXCTL 0x00
24#define B43legacy_DMA32_TXENABLE 0x00000001
25#define B43legacy_DMA32_TXSUSPEND 0x00000002
26#define B43legacy_DMA32_TXLOOPBACK 0x00000004
27#define B43legacy_DMA32_TXFLUSH 0x00000010
28#define B43legacy_DMA32_TXADDREXT_MASK 0x00030000
29#define B43legacy_DMA32_TXADDREXT_SHIFT 16
30#define B43legacy_DMA32_TXRING 0x04
31#define B43legacy_DMA32_TXINDEX 0x08
32#define B43legacy_DMA32_TXSTATUS 0x0C
33#define B43legacy_DMA32_TXDPTR 0x00000FFF
34#define B43legacy_DMA32_TXSTATE 0x0000F000
35#define B43legacy_DMA32_TXSTAT_DISABLED 0x00000000
36#define B43legacy_DMA32_TXSTAT_ACTIVE 0x00001000
37#define B43legacy_DMA32_TXSTAT_IDLEWAIT 0x00002000
38#define B43legacy_DMA32_TXSTAT_STOPPED 0x00003000
39#define B43legacy_DMA32_TXSTAT_SUSP 0x00004000
40#define B43legacy_DMA32_TXERROR 0x000F0000
41#define B43legacy_DMA32_TXERR_NOERR 0x00000000
42#define B43legacy_DMA32_TXERR_PROT 0x00010000
43#define B43legacy_DMA32_TXERR_UNDERRUN 0x00020000
44#define B43legacy_DMA32_TXERR_BUFREAD 0x00030000
45#define B43legacy_DMA32_TXERR_DESCREAD 0x00040000
46#define B43legacy_DMA32_TXACTIVE 0xFFF00000
47#define B43legacy_DMA32_RXCTL 0x10
48#define B43legacy_DMA32_RXENABLE 0x00000001
49#define B43legacy_DMA32_RXFROFF_MASK 0x000000FE
50#define B43legacy_DMA32_RXFROFF_SHIFT 1
51#define B43legacy_DMA32_RXDIRECTFIFO 0x00000100
52#define B43legacy_DMA32_RXADDREXT_MASK 0x00030000
53#define B43legacy_DMA32_RXADDREXT_SHIFT 16
54#define B43legacy_DMA32_RXRING 0x14
55#define B43legacy_DMA32_RXINDEX 0x18
56#define B43legacy_DMA32_RXSTATUS 0x1C
57#define B43legacy_DMA32_RXDPTR 0x00000FFF
58#define B43legacy_DMA32_RXSTATE 0x0000F000
59#define B43legacy_DMA32_RXSTAT_DISABLED 0x00000000
60#define B43legacy_DMA32_RXSTAT_ACTIVE 0x00001000
61#define B43legacy_DMA32_RXSTAT_IDLEWAIT 0x00002000
62#define B43legacy_DMA32_RXSTAT_STOPPED 0x00003000
63#define B43legacy_DMA32_RXERROR 0x000F0000
64#define B43legacy_DMA32_RXERR_NOERR 0x00000000
65#define B43legacy_DMA32_RXERR_PROT 0x00010000
66#define B43legacy_DMA32_RXERR_OVERFLOW 0x00020000
67#define B43legacy_DMA32_RXERR_BUFWRITE 0x00030000
68#define B43legacy_DMA32_RXERR_DESCREAD 0x00040000
69#define B43legacy_DMA32_RXACTIVE 0xFFF00000
70
71/* 32-bit DMA descriptor. */
72struct b43legacy_dmadesc32 {
73 __le32 control;
74 __le32 address;
75} __attribute__((__packed__));
76#define B43legacy_DMA32_DCTL_BYTECNT 0x00001FFF
77#define B43legacy_DMA32_DCTL_ADDREXT_MASK 0x00030000
78#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT 16
79#define B43legacy_DMA32_DCTL_DTABLEEND 0x10000000
80#define B43legacy_DMA32_DCTL_IRQ 0x20000000
81#define B43legacy_DMA32_DCTL_FRAMEEND 0x40000000
82#define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000
83
84
85
86/*** 64-bit DMA Engine. ***/
87
88/* 64-bit DMA controller registers. */
89#define B43legacy_DMA64_TXCTL 0x00
90#define B43legacy_DMA64_TXENABLE 0x00000001
91#define B43legacy_DMA64_TXSUSPEND 0x00000002
92#define B43legacy_DMA64_TXLOOPBACK 0x00000004
93#define B43legacy_DMA64_TXFLUSH 0x00000010
94#define B43legacy_DMA64_TXADDREXT_MASK 0x00030000
95#define B43legacy_DMA64_TXADDREXT_SHIFT 16
96#define B43legacy_DMA64_TXINDEX 0x04
97#define B43legacy_DMA64_TXRINGLO 0x08
98#define B43legacy_DMA64_TXRINGHI 0x0C
99#define B43legacy_DMA64_TXSTATUS 0x10
100#define B43legacy_DMA64_TXSTATDPTR 0x00001FFF
101#define B43legacy_DMA64_TXSTAT 0xF0000000
102#define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000
103#define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000
104#define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000
105#define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000
106#define B43legacy_DMA64_TXSTAT_SUSP 0x40000000
107#define B43legacy_DMA64_TXERROR 0x14
108#define B43legacy_DMA64_TXERRDPTR 0x0001FFFF
109#define B43legacy_DMA64_TXERR 0xF0000000
110#define B43legacy_DMA64_TXERR_NOERR 0x00000000
111#define B43legacy_DMA64_TXERR_PROT 0x10000000
112#define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000
113#define B43legacy_DMA64_TXERR_TRANSFER 0x30000000
114#define B43legacy_DMA64_TXERR_DESCREAD 0x40000000
115#define B43legacy_DMA64_TXERR_CORE 0x50000000
116#define B43legacy_DMA64_RXCTL 0x20
117#define B43legacy_DMA64_RXENABLE 0x00000001
118#define B43legacy_DMA64_RXFROFF_MASK 0x000000FE
119#define B43legacy_DMA64_RXFROFF_SHIFT 1
120#define B43legacy_DMA64_RXDIRECTFIFO 0x00000100
121#define B43legacy_DMA64_RXADDREXT_MASK 0x00030000
122#define B43legacy_DMA64_RXADDREXT_SHIFT 16
123#define B43legacy_DMA64_RXINDEX 0x24
124#define B43legacy_DMA64_RXRINGLO 0x28
125#define B43legacy_DMA64_RXRINGHI 0x2C
126#define B43legacy_DMA64_RXSTATUS 0x30
127#define B43legacy_DMA64_RXSTATDPTR 0x00001FFF
128#define B43legacy_DMA64_RXSTAT 0xF0000000
129#define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000
130#define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000
131#define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000
132#define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000
133#define B43legacy_DMA64_RXSTAT_SUSP 0x40000000
134#define B43legacy_DMA64_RXERROR 0x34
135#define B43legacy_DMA64_RXERRDPTR 0x0001FFFF
136#define B43legacy_DMA64_RXERR 0xF0000000
137#define B43legacy_DMA64_RXERR_NOERR 0x00000000
138#define B43legacy_DMA64_RXERR_PROT 0x10000000
139#define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000
140#define B43legacy_DMA64_RXERR_TRANSFER 0x30000000
141#define B43legacy_DMA64_RXERR_DESCREAD 0x40000000
142#define B43legacy_DMA64_RXERR_CORE 0x50000000
143
144/* 64-bit DMA descriptor. */
145struct b43legacy_dmadesc64 {
146 __le32 control0;
147 __le32 control1;
148 __le32 address_low;
149 __le32 address_high;
150} __attribute__((__packed__));
151#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000
152#define B43legacy_DMA64_DCTL0_IRQ 0x20000000
153#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000
154#define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000
155#define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF
156#define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000
157#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16
158
159
160
161struct b43legacy_dmadesc_generic {
162 union {
163 struct b43legacy_dmadesc32 dma32;
164 struct b43legacy_dmadesc64 dma64;
165 } __attribute__((__packed__));
166} __attribute__((__packed__));
167
168
169/* Misc DMA constants */
170#define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE
171#define B43legacy_DMA0_RX_FRAMEOFFSET 30
172#define B43legacy_DMA3_RX_FRAMEOFFSET 0
173
174
175/* DMA engine tuning knobs */
176#define B43legacy_TXRING_SLOTS 128
177#define B43legacy_RXRING_SLOTS 64
178#define B43legacy_DMA0_RX_BUFFERSIZE (2304 + 100)
179#define B43legacy_DMA3_RX_BUFFERSIZE 16
180
181
182
183#ifdef CONFIG_B43LEGACY_DMA
184
185
186struct sk_buff;
187struct b43legacy_private;
188struct b43legacy_txstatus;
189
190
191struct b43legacy_dmadesc_meta {
192 /* The kernel DMA-able buffer. */
193 struct sk_buff *skb;
194 /* DMA base bus-address of the descriptor buffer. */
195 dma_addr_t dmaaddr;
196 /* ieee80211 TX status. Only used once per 802.11 frag. */
197 bool is_last_fragment;
198 struct ieee80211_tx_status txstat;
199};
200
201struct b43legacy_dmaring;
202
203/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
204struct b43legacy_dma_ops {
205 struct b43legacy_dmadesc_generic * (*idx2desc)
206 (struct b43legacy_dmaring *ring,
207 int slot,
208 struct b43legacy_dmadesc_meta
209 **meta);
210 void (*fill_descriptor)(struct b43legacy_dmaring *ring,
211 struct b43legacy_dmadesc_generic *desc,
212 dma_addr_t dmaaddr, u16 bufsize,
213 int start, int end, int irq);
214 void (*poke_tx)(struct b43legacy_dmaring *ring, int slot);
215 void (*tx_suspend)(struct b43legacy_dmaring *ring);
216 void (*tx_resume)(struct b43legacy_dmaring *ring);
217 int (*get_current_rxslot)(struct b43legacy_dmaring *ring);
218 void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
219};
220
221struct b43legacy_dmaring {
222 /* Lowlevel DMA ops. */
223 const struct b43legacy_dma_ops *ops;
224 /* Kernel virtual base address of the ring memory. */
225 void *descbase;
226 /* Meta data about all descriptors. */
227 struct b43legacy_dmadesc_meta *meta;
228 /* Cache of TX headers for each slot.
229 * This is to avoid an allocation on each TX.
230 * This is NULL for an RX ring.
231 */
232 u8 *txhdr_cache;
233 /* (Unadjusted) DMA base bus-address of the ring memory. */
234 dma_addr_t dmabase;
235 /* Number of descriptor slots in the ring. */
236 int nr_slots;
237 /* Number of used descriptor slots. */
238 int used_slots;
239 /* Currently used slot in the ring. */
240 int current_slot;
241 /* Total number of packets sent. Statistics only. */
242 unsigned int nr_tx_packets;
243 /* Frameoffset in octets. */
244 u32 frameoffset;
245 /* Descriptor buffer size. */
246 u16 rx_buffersize;
247 /* The MMIO base register of the DMA controller. */
248 u16 mmio_base;
249 /* DMA controller index number (0-5). */
250 int index;
251 /* Boolean. Is this a TX ring? */
252 bool tx;
253 /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
254 bool dma64;
255 /* Boolean. Is this ring stopped at ieee80211 level? */
256 bool stopped;
257 /* Lock, only used for TX. */
258 spinlock_t lock;
259 struct b43legacy_wldev *dev;
260#ifdef CONFIG_B43LEGACY_DEBUG
261 /* Maximum number of used slots. */
262 int max_used_slots;
263 /* Last time we injected a ring overflow. */
264 unsigned long last_injected_overflow;
265#endif /* CONFIG_B43LEGACY_DEBUG*/
266};
267
268
269static inline
270u32 b43legacy_dma_read(struct b43legacy_dmaring *ring,
271 u16 offset)
272{
273 return b43legacy_read32(ring->dev, ring->mmio_base + offset);
274}
275
276static inline
277void b43legacy_dma_write(struct b43legacy_dmaring *ring,
278 u16 offset, u32 value)
279{
280 b43legacy_write32(ring->dev, ring->mmio_base + offset, value);
281}
282
283
284int b43legacy_dma_init(struct b43legacy_wldev *dev);
285void b43legacy_dma_free(struct b43legacy_wldev *dev);
286
287int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
288 u16 dmacontroller_mmio_base,
289 int dma64);
290int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
291 u16 dmacontroller_mmio_base,
292 int dma64);
293
294u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx);
295
296void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev);
297void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev);
298
299void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
300 struct ieee80211_tx_queue_stats *stats);
301
302int b43legacy_dma_tx(struct b43legacy_wldev *dev,
303 struct sk_buff *skb,
304 struct ieee80211_tx_control *ctl);
305void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
306 const struct b43legacy_txstatus *status);
307
308void b43legacy_dma_rx(struct b43legacy_dmaring *ring);
309
310#else /* CONFIG_B43LEGACY_DMA */
311
312
313static inline
314int b43legacy_dma_init(struct b43legacy_wldev *dev)
315{
316 return 0;
317}
318static inline
319void b43legacy_dma_free(struct b43legacy_wldev *dev)
320{
321}
322static inline
323int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
324 u16 dmacontroller_mmio_base,
325 int dma64)
326{
327 return 0;
328}
329static inline
330int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
331 u16 dmacontroller_mmio_base,
332 int dma64)
333{
334 return 0;
335}
336static inline
337void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
338 struct ieee80211_tx_queue_stats *stats)
339{
340}
341static inline
342int b43legacy_dma_tx(struct b43legacy_wldev *dev,
343 struct sk_buff *skb,
344 struct ieee80211_tx_control *ctl)
345{
346 return 0;
347}
348static inline
349void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
350 const struct b43legacy_txstatus *status)
351{
352}
353static inline
354void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
355{
356}
357static inline
358void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
359{
360}
361static inline
362void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
363{
364}
365
366#endif /* CONFIG_B43LEGACY_DMA */
367#endif /* B43legacy_DMA_H_ */
diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c
new file mode 100644
index 00000000000..247fc780ffd
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.c
@@ -0,0 +1,336 @@
1/*
2
3 Broadcom B43legacy 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 "b43legacy.h"
29#include "ilt.h"
30#include "phy.h"
31
32
33/**** Initial Internal Lookup Tables ****/
34
35const u32 b43legacy_ilt_rotor[B43legacy_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 b43legacy_ilt_retard[B43legacy_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 b43legacy_ilt_finefreqa[B43legacy_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 b43legacy_ilt_finefreqg[B43legacy_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 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE] = {
230 0x0001, 0x0001, 0x0001, 0xFFFE,
231 0xFFFE, 0x3FFF, 0x1000, 0x0393,
232};
233
234const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE] = {
235 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
236 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
237};
238
239const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE] = {
240 0x013C, 0x01F5, 0x031A, 0x0631,
241 0x0001, 0x0001, 0x0001, 0x0001,
242};
243
244const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE] = {
245 0x5484, 0x3C40, 0x0000, 0x0000,
246 0x0000, 0x0000, 0x0000, 0x0000,
247};
248
249const u16 b43legacy_ilt_noisescaleg1[B43legacy_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 b43legacy_ilt_noisescaleg2[B43legacy_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 b43legacy_ilt_noisescaleg3[B43legacy_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 b43legacy_ilt_sigmasqr1[B43legacy_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 b43legacy_ilt_sigmasqr2[B43legacy_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 b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
316{
317 b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
318 mmiowb();
319 b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, val);
320}
321
322void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, u32 val)
323{
324 b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
325 mmiowb();
326 b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA2,
327 (val & 0xFFFF0000) >> 16);
328 b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1,
329 val & 0x0000FFFF);
330}
331
332u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset)
333{
334 b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
335 return b43legacy_phy_read(dev, B43legacy_PHY_ILT_G_DATA1);
336}
diff --git a/drivers/net/wireless/b43legacy/ilt.h b/drivers/net/wireless/b43legacy/ilt.h
new file mode 100644
index 00000000000..48bcf37eccb
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.h
@@ -0,0 +1,34 @@
1#ifndef B43legacy_ILT_H_
2#define B43legacy_ILT_H_
3
4#define B43legacy_ILT_ROTOR_SIZE 53
5extern const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE];
6#define B43legacy_ILT_RETARD_SIZE 53
7extern const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE];
8#define B43legacy_ILT_FINEFREQA_SIZE 256
9extern const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE];
10#define B43legacy_ILT_FINEFREQG_SIZE 256
11extern const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE];
12#define B43legacy_ILT_NOISEA2_SIZE 8
13extern const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE];
14#define B43legacy_ILT_NOISEA3_SIZE 8
15extern const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE];
16#define B43legacy_ILT_NOISEG1_SIZE 8
17extern const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE];
18#define B43legacy_ILT_NOISEG2_SIZE 8
19extern const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE];
20#define B43legacy_ILT_NOISESCALEG_SIZE 27
21extern const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE];
22extern const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE];
23extern const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE];
24#define B43legacy_ILT_SIGMASQR_SIZE 53
25extern const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE];
26extern const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE];
27
28
29void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
30void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset,
31 u32 val);
32u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset);
33
34#endif /* B43legacy_ILT_H_ */
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
new file mode 100644
index 00000000000..498912ddedd
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.c
@@ -0,0 +1,302 @@
1/*
2
3 Broadcom B43legacy wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mb@bu3sch.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10 Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
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 "leds.h"
30#include "b43legacy.h"
31#include "main.h"
32
33static void b43legacy_led_changestate(struct b43legacy_led *led)
34{
35 struct b43legacy_wldev *dev = led->dev;
36 const int index = led->index;
37 u16 ledctl;
38
39 B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
40 B43legacy_WARN_ON(!led->blink_interval);
41 ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
42 ledctl ^= (1 << index);
43 b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
44}
45
46static void b43legacy_led_blink(unsigned long d)
47{
48 struct b43legacy_led *led = (struct b43legacy_led *)d;
49 struct b43legacy_wldev *dev = led->dev;
50 unsigned long flags;
51
52 spin_lock_irqsave(&dev->wl->leds_lock, flags);
53 if (led->blink_interval) {
54 b43legacy_led_changestate(led);
55 mod_timer(&led->blink_timer, jiffies + led->blink_interval);
56 }
57 spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
58}
59
60static void b43legacy_led_blink_start(struct b43legacy_led *led,
61 unsigned long interval)
62{
63 if (led->blink_interval)
64 return;
65 led->blink_interval = interval;
66 b43legacy_led_changestate(led);
67 led->blink_timer.expires = jiffies + interval;
68 add_timer(&led->blink_timer);
69}
70
71static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync)
72{
73 struct b43legacy_wldev *dev = led->dev;
74 const int index = led->index;
75 u16 ledctl;
76
77 if (!led->blink_interval)
78 return;
79 if (unlikely(sync))
80 del_timer_sync(&led->blink_timer);
81 else
82 del_timer(&led->blink_timer);
83 led->blink_interval = 0;
84
85 /* Make sure the LED is turned off. */
86 B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
87 ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
88 if (led->activelow)
89 ledctl |= (1 << index);
90 else
91 ledctl &= ~(1 << index);
92 b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
93}
94
95static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev,
96 struct b43legacy_led *led,
97 int led_index)
98{
99 struct ssb_bus *bus = dev->dev->bus;
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 B43legacy_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 = B43legacy_LED_ACTIVITY;
111 led->activelow = 1;
112 if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
113 led->behaviour = B43legacy_LED_RADIO_ALL;
114 break;
115 case 1:
116 led->behaviour = B43legacy_LED_RADIO_B;
117 if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
118 led->behaviour = B43legacy_LED_ASSOC;
119 break;
120 case 2:
121 led->behaviour = B43legacy_LED_RADIO_A;
122 break;
123 case 3:
124 led->behaviour = B43legacy_LED_OFF;
125 break;
126 default:
127 B43legacy_BUG_ON(1);
128 }
129}
130
131int b43legacy_leds_init(struct b43legacy_wldev *dev)
132{
133 struct b43legacy_led *led;
134 u8 sprom[4];
135 int i;
136
137 sprom[0] = dev->dev->bus->sprom.r1.gpio0;
138 sprom[1] = dev->dev->bus->sprom.r1.gpio1;
139 sprom[2] = dev->dev->bus->sprom.r1.gpio2;
140 sprom[3] = dev->dev->bus->sprom.r1.gpio3;
141
142 for (i = 0; i < B43legacy_NR_LEDS; i++) {
143 led = &(dev->leds[i]);
144 led->index = i;
145 led->dev = dev;
146 setup_timer(&led->blink_timer,
147 b43legacy_led_blink,
148 (unsigned long)led);
149
150 if (sprom[i] == 0xFF)
151 b43legacy_led_init_hardcoded(dev, led, i);
152 else {
153 led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR;
154 led->activelow = !!(sprom[i] &
155 B43legacy_LED_ACTIVELOW);
156 }
157 }
158
159 return 0;
160}
161
162void b43legacy_leds_exit(struct b43legacy_wldev *dev)
163{
164 struct b43legacy_led *led;
165 int i;
166
167 for (i = 0; i < B43legacy_NR_LEDS; i++) {
168 led = &(dev->leds[i]);
169 b43legacy_led_blink_stop(led, 1);
170 }
171 b43legacy_leds_switch_all(dev, 0);
172}
173
174void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity)
175{
176 struct b43legacy_led *led;
177 struct b43legacy_phy *phy = &dev->phy;
178 const int transferring = (jiffies - dev->stats.last_tx)
179 < B43legacy_LED_XFER_THRES;
180 int i;
181 int turn_on;
182 unsigned long interval = 0;
183 u16 ledctl;
184 unsigned long flags;
185
186 spin_lock_irqsave(&dev->wl->leds_lock, flags);
187 ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
188 for (i = 0; i < B43legacy_NR_LEDS; i++) {
189 led = &(dev->leds[i]);
190
191 turn_on = 0;
192 switch (led->behaviour) {
193 case B43legacy_LED_INACTIVE:
194 continue;
195 case B43legacy_LED_OFF:
196 break;
197 case B43legacy_LED_ON:
198 turn_on = 1;
199 break;
200 case B43legacy_LED_ACTIVITY:
201 turn_on = activity;
202 break;
203 case B43legacy_LED_RADIO_ALL:
204 turn_on = phy->radio_on &&
205 b43legacy_is_hw_radio_enabled(dev);
206 break;
207 case B43legacy_LED_RADIO_A:
208 break;
209 case B43legacy_LED_RADIO_B:
210 turn_on = (phy->radio_on &&
211 b43legacy_is_hw_radio_enabled(dev) &&
212 (phy->type == B43legacy_PHYTYPE_B ||
213 phy->type == B43legacy_PHYTYPE_G));
214 break;
215 case B43legacy_LED_MODE_BG:
216 if (phy->type == B43legacy_PHYTYPE_G &&
217 b43legacy_is_hw_radio_enabled(dev))
218 turn_on = 1;
219 break;
220 case B43legacy_LED_TRANSFER:
221 if (transferring)
222 b43legacy_led_blink_start(led,
223 B43legacy_LEDBLINK_MEDIUM);
224 else
225 b43legacy_led_blink_stop(led, 0);
226 continue;
227 case B43legacy_LED_APTRANSFER:
228 if (b43legacy_is_mode(dev->wl,
229 IEEE80211_IF_TYPE_AP)) {
230 if (transferring) {
231 interval = B43legacy_LEDBLINK_FAST;
232 turn_on = 1;
233 }
234 } else {
235 turn_on = 1;
236 if (transferring)
237 interval = B43legacy_LEDBLINK_FAST;
238 else
239 turn_on = 0;
240 }
241 if (turn_on)
242 b43legacy_led_blink_start(led, interval);
243 else
244 b43legacy_led_blink_stop(led, 0);
245 continue;
246 case B43legacy_LED_WEIRD:
247 break;
248 case B43legacy_LED_ASSOC:
249 turn_on = 1;
250#ifdef CONFIG_B43LEGACY_DEBUG
251 case B43legacy_LED_TEST_BLINKSLOW:
252 b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW);
253 continue;
254 case B43legacy_LED_TEST_BLINKMEDIUM:
255 b43legacy_led_blink_start(led,
256 B43legacy_LEDBLINK_MEDIUM);
257 continue;
258 case B43legacy_LED_TEST_BLINKFAST:
259 b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST);
260 continue;
261#endif /* CONFIG_B43LEGACY_DEBUG */
262 default:
263 B43legacy_BUG_ON(1);
264 };
265
266 if (led->activelow)
267 turn_on = !turn_on;
268 if (turn_on)
269 ledctl |= (1 << i);
270 else
271 ledctl &= ~(1 << i);
272 }
273 b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
274 spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
275}
276
277void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on)
278{
279 struct b43legacy_led *led;
280 u16 ledctl;
281 int i;
282 int bit_on;
283 unsigned long flags;
284
285 spin_lock_irqsave(&dev->wl->leds_lock, flags);
286 ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
287 for (i = 0; i < B43legacy_NR_LEDS; i++) {
288 led = &(dev->leds[i]);
289 if (led->behaviour == B43legacy_LED_INACTIVE)
290 continue;
291 if (on)
292 bit_on = led->activelow ? 0 : 1;
293 else
294 bit_on = led->activelow ? 1 : 0;
295 if (bit_on)
296 ledctl |= (1 << i);
297 else
298 ledctl &= ~(1 << i);
299 }
300 b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
301 spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
302}
diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h
new file mode 100644
index 00000000000..b989f503e68
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.h
@@ -0,0 +1,56 @@
1#ifndef B43legacy_LEDS_H_
2#define B43legacy_LEDS_H_
3
4#include <linux/types.h>
5#include <linux/timer.h>
6
7
8struct b43legacy_led {
9 u8 behaviour;
10 bool activelow;
11 /* Index in the "leds" array in b43legacy_wldev */
12 u8 index;
13 struct b43legacy_wldev *dev;
14 struct timer_list blink_timer;
15 unsigned long blink_interval;
16};
17
18/* Delay between state changes when blinking in jiffies */
19#define B43legacy_LEDBLINK_SLOW (HZ / 1)
20#define B43legacy_LEDBLINK_MEDIUM (HZ / 4)
21#define B43legacy_LEDBLINK_FAST (HZ / 8)
22
23#define B43legacy_LED_XFER_THRES (HZ / 100)
24
25#define B43legacy_LED_BEHAVIOUR 0x7F
26#define B43legacy_LED_ACTIVELOW 0x80
27enum { /* LED behaviour values */
28 B43legacy_LED_OFF,
29 B43legacy_LED_ON,
30 B43legacy_LED_ACTIVITY,
31 B43legacy_LED_RADIO_ALL,
32 B43legacy_LED_RADIO_A,
33 B43legacy_LED_RADIO_B,
34 B43legacy_LED_MODE_BG,
35 B43legacy_LED_TRANSFER,
36 B43legacy_LED_APTRANSFER,
37 B43legacy_LED_WEIRD,
38 B43legacy_LED_ASSOC,
39 B43legacy_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 B43legacy_LED_TEST_BLINKSLOW,
47 B43legacy_LED_TEST_BLINKMEDIUM,
48 B43legacy_LED_TEST_BLINKFAST,
49};
50
51int b43legacy_leds_init(struct b43legacy_wldev *dev);
52void b43legacy_leds_exit(struct b43legacy_wldev *dev);
53void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity);
54void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on);
55
56#endif /* B43legacy_LEDS_H_ */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
new file mode 100644
index 00000000000..ac4831adb57
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -0,0 +1,3805 @@
1/*
2 *
3 * Broadcom B43legacy wireless driver
4 *
5 * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
6 * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
7 * Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
8 * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
9 * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10 * Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
11 *
12 * Some parts of the code in this file are derived from the ipw2200
13 * driver Copyright(c) 2003 - 2004 Intel Corporation.
14
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; see the file COPYING. If not, write to
27 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
28 * Boston, MA 02110-1301, USA.
29 *
30 */
31
32#include <linux/delay.h>
33#include <linux/init.h>
34#include <linux/moduleparam.h>
35#include <linux/if_arp.h>
36#include <linux/etherdevice.h>
37#include <linux/version.h>
38#include <linux/firmware.h>
39#include <linux/wireless.h>
40#include <linux/workqueue.h>
41#include <linux/skbuff.h>
42#include <linux/dma-mapping.h>
43#include <net/dst.h>
44#include <asm/unaligned.h>
45
46#include "b43legacy.h"
47#include "main.h"
48#include "debugfs.h"
49#include "phy.h"
50#include "dma.h"
51#include "pio.h"
52#include "sysfs.h"
53#include "xmit.h"
54#include "radio.h"
55
56
57MODULE_DESCRIPTION("Broadcom B43legacy wireless driver");
58MODULE_AUTHOR("Martin Langer");
59MODULE_AUTHOR("Stefano Brivio");
60MODULE_AUTHOR("Michael Buesch");
61MODULE_LICENSE("GPL");
62
63#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
64static int modparam_pio;
65module_param_named(pio, modparam_pio, int, 0444);
66MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
67#elif defined(CONFIG_B43LEGACY_DMA)
68# define modparam_pio 0
69#elif defined(CONFIG_B43LEGACY_PIO)
70# define modparam_pio 1
71#endif
72
73static int modparam_bad_frames_preempt;
74module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
75MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames"
76 " Preemption");
77
78static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT;
79module_param_named(short_retry, modparam_short_retry, int, 0444);
80MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
81
82static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT;
83module_param_named(long_retry, modparam_long_retry, int, 0444);
84MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
85
86static int modparam_noleds;
87module_param_named(noleds, modparam_noleds, int, 0444);
88MODULE_PARM_DESC(noleds, "Turn off all LED activity");
89
90static char modparam_fwpostfix[16];
91module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
92MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
93
94static int modparam_mon_keep_bad;
95module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444);
96MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode");
97
98static int modparam_mon_keep_badplcp;
99module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444);
100MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode");
101
102/* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */
103static const struct ssb_device_id b43legacy_ssb_tbl[] = {
104 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2),
105 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4),
106 SSB_DEVTABLE_END
107};
108MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl);
109
110
111/* Channel and ratetables are shared for all devices.
112 * They can't be const, because ieee80211 puts some precalculated
113 * data in there. This data is the same for all devices, so we don't
114 * get concurrency issues */
115#define RATETAB_ENT(_rateid, _flags) \
116 { \
117 .rate = B43legacy_RATE_TO_100KBPS(_rateid), \
118 .val = (_rateid), \
119 .val2 = (_rateid), \
120 .flags = (_flags), \
121 }
122static struct ieee80211_rate __b43legacy_ratetable[] = {
123 RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK),
124 RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
125 RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
126 RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
127 RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
128 RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
129 RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
130 RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
131 RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
132 RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
133 RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
134 RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
135};
136#define b43legacy_a_ratetable (__b43legacy_ratetable + 4)
137#define b43legacy_a_ratetable_size 8
138#define b43legacy_b_ratetable (__b43legacy_ratetable + 0)
139#define b43legacy_b_ratetable_size 4
140#define b43legacy_g_ratetable (__b43legacy_ratetable + 0)
141#define b43legacy_g_ratetable_size 12
142
143#define CHANTAB_ENT(_chanid, _freq) \
144 { \
145 .chan = (_chanid), \
146 .freq = (_freq), \
147 .val = (_chanid), \
148 .flag = IEEE80211_CHAN_W_SCAN | \
149 IEEE80211_CHAN_W_ACTIVE_SCAN | \
150 IEEE80211_CHAN_W_IBSS, \
151 .power_level = 0x0A, \
152 .antenna_max = 0xFF, \
153 }
154static struct ieee80211_channel b43legacy_bg_chantable[] = {
155 CHANTAB_ENT(1, 2412),
156 CHANTAB_ENT(2, 2417),
157 CHANTAB_ENT(3, 2422),
158 CHANTAB_ENT(4, 2427),
159 CHANTAB_ENT(5, 2432),
160 CHANTAB_ENT(6, 2437),
161 CHANTAB_ENT(7, 2442),
162 CHANTAB_ENT(8, 2447),
163 CHANTAB_ENT(9, 2452),
164 CHANTAB_ENT(10, 2457),
165 CHANTAB_ENT(11, 2462),
166 CHANTAB_ENT(12, 2467),
167 CHANTAB_ENT(13, 2472),
168 CHANTAB_ENT(14, 2484),
169};
170#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable)
171
172static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev);
173static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev);
174static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev);
175static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev);
176
177
178static int b43legacy_ratelimit(struct b43legacy_wl *wl)
179{
180 if (!wl || !wl->current_dev)
181 return 1;
182 if (b43legacy_status(wl->current_dev) < B43legacy_STAT_STARTED)
183 return 1;
184 /* We are up and running.
185 * Ratelimit the messages to avoid DoS over the net. */
186 return net_ratelimit();
187}
188
189void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
190{
191 va_list args;
192
193 if (!b43legacy_ratelimit(wl))
194 return;
195 va_start(args, fmt);
196 printk(KERN_INFO "b43legacy-%s: ",
197 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
198 vprintk(fmt, args);
199 va_end(args);
200}
201
202void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
203{
204 va_list args;
205
206 if (!b43legacy_ratelimit(wl))
207 return;
208 va_start(args, fmt);
209 printk(KERN_ERR "b43legacy-%s ERROR: ",
210 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
211 vprintk(fmt, args);
212 va_end(args);
213}
214
215void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
216{
217 va_list args;
218
219 if (!b43legacy_ratelimit(wl))
220 return;
221 va_start(args, fmt);
222 printk(KERN_WARNING "b43legacy-%s warning: ",
223 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
224 vprintk(fmt, args);
225 va_end(args);
226}
227
228#if B43legacy_DEBUG
229void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
230{
231 va_list args;
232
233 va_start(args, fmt);
234 printk(KERN_DEBUG "b43legacy-%s debug: ",
235 (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
236 vprintk(fmt, args);
237 va_end(args);
238}
239#endif /* DEBUG */
240
241static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset,
242 u32 val)
243{
244 u32 status;
245
246 B43legacy_WARN_ON(offset % 4 != 0);
247
248 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
249 if (status & B43legacy_SBF_XFER_REG_BYTESWAP)
250 val = swab32(val);
251
252 b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset);
253 mmiowb();
254 b43legacy_write32(dev, B43legacy_MMIO_RAM_DATA, val);
255}
256
257static inline
258void b43legacy_shm_control_word(struct b43legacy_wldev *dev,
259 u16 routing, u16 offset)
260{
261 u32 control;
262
263 /* "offset" is the WORD offset. */
264
265 control = routing;
266 control <<= 16;
267 control |= offset;
268 b43legacy_write32(dev, B43legacy_MMIO_SHM_CONTROL, control);
269}
270
271u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
272 u16 routing, u16 offset)
273{
274 u32 ret;
275
276 if (routing == B43legacy_SHM_SHARED) {
277 B43legacy_WARN_ON((offset & 0x0001) != 0);
278 if (offset & 0x0003) {
279 /* Unaligned access */
280 b43legacy_shm_control_word(dev, routing, offset >> 2);
281 ret = b43legacy_read16(dev,
282 B43legacy_MMIO_SHM_DATA_UNALIGNED);
283 ret <<= 16;
284 b43legacy_shm_control_word(dev, routing,
285 (offset >> 2) + 1);
286 ret |= b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
287
288 return ret;
289 }
290 offset >>= 2;
291 }
292 b43legacy_shm_control_word(dev, routing, offset);
293 ret = b43legacy_read32(dev, B43legacy_MMIO_SHM_DATA);
294
295 return ret;
296}
297
298u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
299 u16 routing, u16 offset)
300{
301 u16 ret;
302
303 if (routing == B43legacy_SHM_SHARED) {
304 B43legacy_WARN_ON((offset & 0x0001) != 0);
305 if (offset & 0x0003) {
306 /* Unaligned access */
307 b43legacy_shm_control_word(dev, routing, offset >> 2);
308 ret = b43legacy_read16(dev,
309 B43legacy_MMIO_SHM_DATA_UNALIGNED);
310
311 return ret;
312 }
313 offset >>= 2;
314 }
315 b43legacy_shm_control_word(dev, routing, offset);
316 ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
317
318 return ret;
319}
320
321void b43legacy_shm_write32(struct b43legacy_wldev *dev,
322 u16 routing, u16 offset,
323 u32 value)
324{
325 if (routing == B43legacy_SHM_SHARED) {
326 B43legacy_WARN_ON((offset & 0x0001) != 0);
327 if (offset & 0x0003) {
328 /* Unaligned access */
329 b43legacy_shm_control_word(dev, routing, offset >> 2);
330 mmiowb();
331 b43legacy_write16(dev,
332 B43legacy_MMIO_SHM_DATA_UNALIGNED,
333 (value >> 16) & 0xffff);
334 mmiowb();
335 b43legacy_shm_control_word(dev, routing,
336 (offset >> 2) + 1);
337 mmiowb();
338 b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA,
339 value & 0xffff);
340 return;
341 }
342 offset >>= 2;
343 }
344 b43legacy_shm_control_word(dev, routing, offset);
345 mmiowb();
346 b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, value);
347}
348
349void b43legacy_shm_write16(struct b43legacy_wldev *dev, u16 routing, u16 offset,
350 u16 value)
351{
352 if (routing == B43legacy_SHM_SHARED) {
353 B43legacy_WARN_ON((offset & 0x0001) != 0);
354 if (offset & 0x0003) {
355 /* Unaligned access */
356 b43legacy_shm_control_word(dev, routing, offset >> 2);
357 mmiowb();
358 b43legacy_write16(dev,
359 B43legacy_MMIO_SHM_DATA_UNALIGNED,
360 value);
361 return;
362 }
363 offset >>= 2;
364 }
365 b43legacy_shm_control_word(dev, routing, offset);
366 mmiowb();
367 b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value);
368}
369
370/* Read HostFlags */
371u32 b43legacy_hf_read(struct b43legacy_wldev *dev)
372{
373 u32 ret;
374
375 ret = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
376 B43legacy_SHM_SH_HOSTFHI);
377 ret <<= 16;
378 ret |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
379 B43legacy_SHM_SH_HOSTFLO);
380
381 return ret;
382}
383
384/* Write HostFlags */
385void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value)
386{
387 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
388 B43legacy_SHM_SH_HOSTFLO,
389 (value & 0x0000FFFF));
390 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
391 B43legacy_SHM_SH_HOSTFHI,
392 ((value & 0xFFFF0000) >> 16));
393}
394
395void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf)
396{
397 /* We need to be careful. As we read the TSF from multiple
398 * registers, we should take care of register overflows.
399 * In theory, the whole tsf read process should be atomic.
400 * We try to be atomic here, by restaring the read process,
401 * if any of the high registers changed (overflew).
402 */
403 if (dev->dev->id.revision >= 3) {
404 u32 low;
405 u32 high;
406 u32 high2;
407
408 do {
409 high = b43legacy_read32(dev,
410 B43legacy_MMIO_REV3PLUS_TSF_HIGH);
411 low = b43legacy_read32(dev,
412 B43legacy_MMIO_REV3PLUS_TSF_LOW);
413 high2 = b43legacy_read32(dev,
414 B43legacy_MMIO_REV3PLUS_TSF_HIGH);
415 } while (unlikely(high != high2));
416
417 *tsf = high;
418 *tsf <<= 32;
419 *tsf |= low;
420 } else {
421 u64 tmp;
422 u16 v0;
423 u16 v1;
424 u16 v2;
425 u16 v3;
426 u16 test1;
427 u16 test2;
428 u16 test3;
429
430 do {
431 v3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
432 v2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
433 v1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
434 v0 = b43legacy_read16(dev, B43legacy_MMIO_TSF_0);
435
436 test3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
437 test2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
438 test1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
439 } while (v3 != test3 || v2 != test2 || v1 != test1);
440
441 *tsf = v3;
442 *tsf <<= 48;
443 tmp = v2;
444 tmp <<= 32;
445 *tsf |= tmp;
446 tmp = v1;
447 tmp <<= 16;
448 *tsf |= tmp;
449 *tsf |= v0;
450 }
451}
452
453static void b43legacy_time_lock(struct b43legacy_wldev *dev)
454{
455 u32 status;
456
457 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
458 status |= B43legacy_SBF_TIME_UPDATE;
459 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
460 mmiowb();
461}
462
463static void b43legacy_time_unlock(struct b43legacy_wldev *dev)
464{
465 u32 status;
466
467 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
468 status &= ~B43legacy_SBF_TIME_UPDATE;
469 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
470}
471
472static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf)
473{
474 /* Be careful with the in-progress timer.
475 * First zero out the low register, so we have a full
476 * register-overflow duration to complete the operation.
477 */
478 if (dev->dev->id.revision >= 3) {
479 u32 lo = (tsf & 0x00000000FFFFFFFFULL);
480 u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
481
482 b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, 0);
483 mmiowb();
484 b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH,
485 hi);
486 mmiowb();
487 b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW,
488 lo);
489 } else {
490 u16 v0 = (tsf & 0x000000000000FFFFULL);
491 u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
492 u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
493 u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
494
495 b43legacy_write16(dev, B43legacy_MMIO_TSF_0, 0);
496 mmiowb();
497 b43legacy_write16(dev, B43legacy_MMIO_TSF_3, v3);
498 mmiowb();
499 b43legacy_write16(dev, B43legacy_MMIO_TSF_2, v2);
500 mmiowb();
501 b43legacy_write16(dev, B43legacy_MMIO_TSF_1, v1);
502 mmiowb();
503 b43legacy_write16(dev, B43legacy_MMIO_TSF_0, v0);
504 }
505}
506
507void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf)
508{
509 b43legacy_time_lock(dev);
510 b43legacy_tsf_write_locked(dev, tsf);
511 b43legacy_time_unlock(dev);
512}
513
514static
515void b43legacy_macfilter_set(struct b43legacy_wldev *dev,
516 u16 offset, const u8 *mac)
517{
518 static const u8 zero_addr[ETH_ALEN] = { 0 };
519 u16 data;
520
521 if (!mac)
522 mac = zero_addr;
523
524 offset |= 0x0020;
525 b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_CONTROL, offset);
526
527 data = mac[0];
528 data |= mac[1] << 8;
529 b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
530 data = mac[2];
531 data |= mac[3] << 8;
532 b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
533 data = mac[4];
534 data |= mac[5] << 8;
535 b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
536}
537
538static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev)
539{
540 static const u8 zero_addr[ETH_ALEN] = { 0 };
541 const u8 *mac = dev->wl->mac_addr;
542 const u8 *bssid = dev->wl->bssid;
543 u8 mac_bssid[ETH_ALEN * 2];
544 int i;
545 u32 tmp;
546
547 if (!bssid)
548 bssid = zero_addr;
549 if (!mac)
550 mac = zero_addr;
551
552 b43legacy_macfilter_set(dev, B43legacy_MACFILTER_BSSID, bssid);
553
554 memcpy(mac_bssid, mac, ETH_ALEN);
555 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
556
557 /* Write our MAC address and BSSID to template ram */
558 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
559 tmp = (u32)(mac_bssid[i + 0]);
560 tmp |= (u32)(mac_bssid[i + 1]) << 8;
561 tmp |= (u32)(mac_bssid[i + 2]) << 16;
562 tmp |= (u32)(mac_bssid[i + 3]) << 24;
563 b43legacy_ram_write(dev, 0x20 + i, tmp);
564 b43legacy_ram_write(dev, 0x78 + i, tmp);
565 b43legacy_ram_write(dev, 0x478 + i, tmp);
566 }
567}
568
569static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev,
570 const u8 *mac_addr)
571{
572 dev->wl->mac_addr = mac_addr;
573 b43legacy_write_mac_bssid_templates(dev);
574 b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr);
575}
576
577static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
578 u16 slot_time)
579{
580 /* slot_time is in usec. */
581 if (dev->phy.type != B43legacy_PHYTYPE_G)
582 return;
583 b43legacy_write16(dev, 0x684, 510 + slot_time);
584 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0010,
585 slot_time);
586}
587
588static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev)
589{
590 b43legacy_set_slot_time(dev, 9);
591 dev->short_slot = 1;
592}
593
594static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
595{
596 b43legacy_set_slot_time(dev, 20);
597 dev->short_slot = 0;
598}
599
600/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
601 * Returns the _previously_ enabled IRQ mask.
602 */
603static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev,
604 u32 mask)
605{
606 u32 old_mask;
607
608 old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
609 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask |
610 mask);
611
612 return old_mask;
613}
614
615/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
616 * Returns the _previously_ enabled IRQ mask.
617 */
618static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev,
619 u32 mask)
620{
621 u32 old_mask;
622
623 old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
624 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
625
626 return old_mask;
627}
628
629/* Synchronize IRQ top- and bottom-half.
630 * IRQs must be masked before calling this.
631 * This must not be called with the irq_lock held.
632 */
633static void b43legacy_synchronize_irq(struct b43legacy_wldev *dev)
634{
635 synchronize_irq(dev->dev->irq);
636 tasklet_kill(&dev->isr_tasklet);
637}
638
639/* DummyTransmission function, as documented on
640 * http://bcm-specs.sipsolutions.net/DummyTransmission
641 */
642void b43legacy_dummy_transmission(struct b43legacy_wldev *dev)
643{
644 struct b43legacy_phy *phy = &dev->phy;
645 unsigned int i;
646 unsigned int max_loop;
647 u16 value;
648 u32 buffer[5] = {
649 0x00000000,
650 0x00D40000,
651 0x00000000,
652 0x01000000,
653 0x00000000,
654 };
655
656 switch (phy->type) {
657 case B43legacy_PHYTYPE_B:
658 case B43legacy_PHYTYPE_G:
659 max_loop = 0xFA;
660 buffer[0] = 0x000B846E;
661 break;
662 default:
663 B43legacy_BUG_ON(1);
664 return;
665 }
666
667 for (i = 0; i < 5; i++)
668 b43legacy_ram_write(dev, i * 4, buffer[i]);
669
670 /* dummy read follows */
671 b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
672
673 b43legacy_write16(dev, 0x0568, 0x0000);
674 b43legacy_write16(dev, 0x07C0, 0x0000);
675 b43legacy_write16(dev, 0x050C, 0x0000);
676 b43legacy_write16(dev, 0x0508, 0x0000);
677 b43legacy_write16(dev, 0x050A, 0x0000);
678 b43legacy_write16(dev, 0x054C, 0x0000);
679 b43legacy_write16(dev, 0x056A, 0x0014);
680 b43legacy_write16(dev, 0x0568, 0x0826);
681 b43legacy_write16(dev, 0x0500, 0x0000);
682 b43legacy_write16(dev, 0x0502, 0x0030);
683
684 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
685 b43legacy_radio_write16(dev, 0x0051, 0x0017);
686 for (i = 0x00; i < max_loop; i++) {
687 value = b43legacy_read16(dev, 0x050E);
688 if (value & 0x0080)
689 break;
690 udelay(10);
691 }
692 for (i = 0x00; i < 0x0A; i++) {
693 value = b43legacy_read16(dev, 0x050E);
694 if (value & 0x0400)
695 break;
696 udelay(10);
697 }
698 for (i = 0x00; i < 0x0A; i++) {
699 value = b43legacy_read16(dev, 0x0690);
700 if (!(value & 0x0100))
701 break;
702 udelay(10);
703 }
704 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
705 b43legacy_radio_write16(dev, 0x0051, 0x0037);
706}
707
708/* Turn the Analog ON/OFF */
709static void b43legacy_switch_analog(struct b43legacy_wldev *dev, int on)
710{
711 b43legacy_write16(dev, B43legacy_MMIO_PHY0, on ? 0 : 0xF4);
712}
713
714void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags)
715{
716 u32 tmslow;
717 u32 macctl;
718
719 flags |= B43legacy_TMSLOW_PHYCLKEN;
720 flags |= B43legacy_TMSLOW_PHYRESET;
721 ssb_device_enable(dev->dev, flags);
722 msleep(2); /* Wait for the PLL to turn on. */
723
724 /* Now take the PHY out of Reset again */
725 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
726 tmslow |= SSB_TMSLOW_FGC;
727 tmslow &= ~B43legacy_TMSLOW_PHYRESET;
728 ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
729 ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
730 msleep(1);
731 tmslow &= ~SSB_TMSLOW_FGC;
732 ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
733 ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
734 msleep(1);
735
736 /* Turn Analog ON */
737 b43legacy_switch_analog(dev, 1);
738
739 macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
740 macctl &= ~B43legacy_MACCTL_GMODE;
741 if (flags & B43legacy_TMSLOW_GMODE) {
742 macctl |= B43legacy_MACCTL_GMODE;
743 dev->phy.gmode = 1;
744 } else
745 dev->phy.gmode = 0;
746 macctl |= B43legacy_MACCTL_IHR_ENABLED;
747 b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
748}
749
750static void handle_irq_transmit_status(struct b43legacy_wldev *dev)
751{
752 u32 v0;
753 u32 v1;
754 u16 tmp;
755 struct b43legacy_txstatus stat;
756
757 while (1) {
758 v0 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
759 if (!(v0 & 0x00000001))
760 break;
761 v1 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
762
763 stat.cookie = (v0 >> 16);
764 stat.seq = (v1 & 0x0000FFFF);
765 stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
766 tmp = (v0 & 0x0000FFFF);
767 stat.frame_count = ((tmp & 0xF000) >> 12);
768 stat.rts_count = ((tmp & 0x0F00) >> 8);
769 stat.supp_reason = ((tmp & 0x001C) >> 2);
770 stat.pm_indicated = !!(tmp & 0x0080);
771 stat.intermediate = !!(tmp & 0x0040);
772 stat.for_ampdu = !!(tmp & 0x0020);
773 stat.acked = !!(tmp & 0x0002);
774
775 b43legacy_handle_txstatus(dev, &stat);
776 }
777}
778
779static void drain_txstatus_queue(struct b43legacy_wldev *dev)
780{
781 u32 dummy;
782
783 if (dev->dev->id.revision < 5)
784 return;
785 /* Read all entries from the microcode TXstatus FIFO
786 * and throw them away.
787 */
788 while (1) {
789 dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
790 if (!(dummy & 0x00000001))
791 break;
792 dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
793 }
794}
795
796static u32 b43legacy_jssi_read(struct b43legacy_wldev *dev)
797{
798 u32 val = 0;
799
800 val = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x40A);
801 val <<= 16;
802 val |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x408);
803
804 return val;
805}
806
807static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi)
808{
809 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x408,
810 (jssi & 0x0000FFFF));
811 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x40A,
812 (jssi & 0xFFFF0000) >> 16);
813}
814
815static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev)
816{
817 b43legacy_jssi_write(dev, 0x7F7F7F7F);
818 b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
819 b43legacy_read32(dev,
820 B43legacy_MMIO_STATUS2_BITFIELD)
821 | (1 << 4));
822 B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
823 dev->phy.channel);
824}
825
826static void b43legacy_calculate_link_quality(struct b43legacy_wldev *dev)
827{
828 /* Top half of Link Quality calculation. */
829
830 if (dev->noisecalc.calculation_running)
831 return;
832 dev->noisecalc.channel_at_start = dev->phy.channel;
833 dev->noisecalc.calculation_running = 1;
834 dev->noisecalc.nr_samples = 0;
835
836 b43legacy_generate_noise_sample(dev);
837}
838
839static void handle_irq_noise(struct b43legacy_wldev *dev)
840{
841 struct b43legacy_phy *phy = &dev->phy;
842 u16 tmp;
843 u8 noise[4];
844 u8 i;
845 u8 j;
846 s32 average;
847
848 /* Bottom half of Link Quality calculation. */
849
850 B43legacy_WARN_ON(!dev->noisecalc.calculation_running);
851 if (dev->noisecalc.channel_at_start != phy->channel)
852 goto drop_calculation;
853 *((__le32 *)noise) = cpu_to_le32(b43legacy_jssi_read(dev));
854 if (noise[0] == 0x7F || noise[1] == 0x7F ||
855 noise[2] == 0x7F || noise[3] == 0x7F)
856 goto generate_new;
857
858 /* Get the noise samples. */
859 B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8);
860 i = dev->noisecalc.nr_samples;
861 noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
862 noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
863 noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
864 noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
865 dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
866 dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
867 dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
868 dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
869 dev->noisecalc.nr_samples++;
870 if (dev->noisecalc.nr_samples == 8) {
871 /* Calculate the Link Quality by the noise samples. */
872 average = 0;
873 for (i = 0; i < 8; i++) {
874 for (j = 0; j < 4; j++)
875 average += dev->noisecalc.samples[i][j];
876 }
877 average /= (8 * 4);
878 average *= 125;
879 average += 64;
880 average /= 128;
881 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
882 0x40C);
883 tmp = (tmp / 128) & 0x1F;
884 if (tmp >= 8)
885 average += 2;
886 else
887 average -= 25;
888 if (tmp == 8)
889 average -= 72;
890 else
891 average -= 48;
892
893 dev->stats.link_noise = average;
894drop_calculation:
895 dev->noisecalc.calculation_running = 0;
896 return;
897 }
898generate_new:
899 b43legacy_generate_noise_sample(dev);
900}
901
902static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev)
903{
904 if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
905 /* TODO: PS TBTT */
906 } else {
907 if (1/*FIXME: the last PSpoll frame was sent successfully */)
908 b43legacy_power_saving_ctl_bits(dev, -1, -1);
909 }
910 dev->reg124_set_0x4 = 0;
911 if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
912 dev->reg124_set_0x4 = 1;
913}
914
915static void handle_irq_atim_end(struct b43legacy_wldev *dev)
916{
917 if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
918 return;
919 b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
920 b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD)
921 | 0x4);
922}
923
924static void handle_irq_pmq(struct b43legacy_wldev *dev)
925{
926 u32 tmp;
927
928 /* TODO: AP mode. */
929
930 while (1) {
931 tmp = b43legacy_read32(dev, B43legacy_MMIO_PS_STATUS);
932 if (!(tmp & 0x00000008))
933 break;
934 }
935 /* 16bit write is odd, but correct. */
936 b43legacy_write16(dev, B43legacy_MMIO_PS_STATUS, 0x0002);
937}
938
939static void b43legacy_write_template_common(struct b43legacy_wldev *dev,
940 const u8 *data, u16 size,
941 u16 ram_offset,
942 u16 shm_size_offset, u8 rate)
943{
944 u32 i;
945 u32 tmp;
946 struct b43legacy_plcp_hdr4 plcp;
947
948 plcp.data = 0;
949 b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
950 b43legacy_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
951 ram_offset += sizeof(u32);
952 /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
953 * So leave the first two bytes of the next write blank.
954 */
955 tmp = (u32)(data[0]) << 16;
956 tmp |= (u32)(data[1]) << 24;
957 b43legacy_ram_write(dev, ram_offset, tmp);
958 ram_offset += sizeof(u32);
959 for (i = 2; i < size; i += sizeof(u32)) {
960 tmp = (u32)(data[i + 0]);
961 if (i + 1 < size)
962 tmp |= (u32)(data[i + 1]) << 8;
963 if (i + 2 < size)
964 tmp |= (u32)(data[i + 2]) << 16;
965 if (i + 3 < size)
966 tmp |= (u32)(data[i + 3]) << 24;
967 b43legacy_ram_write(dev, ram_offset + i - 2, tmp);
968 }
969 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_size_offset,
970 size + sizeof(struct b43legacy_plcp_hdr6));
971}
972
973static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
974 u16 ram_offset,
975 u16 shm_size_offset, u8 rate)
976{
977 int len;
978 const u8 *data;
979
980 B43legacy_WARN_ON(!dev->cached_beacon);
981 len = min((size_t)dev->cached_beacon->len,
982 0x200 - sizeof(struct b43legacy_plcp_hdr6));
983 data = (const u8 *)(dev->cached_beacon->data);
984 b43legacy_write_template_common(dev, data,
985 len, ram_offset,
986 shm_size_offset, rate);
987}
988
989static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
990 u16 shm_offset, u16 size,
991 u8 rate)
992{
993 struct b43legacy_plcp_hdr4 plcp;
994 u32 tmp;
995 __le16 dur;
996
997 plcp.data = 0;
998 b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
999 dur = ieee80211_generic_frame_duration(dev->wl->hw,
1000 dev->wl->if_id,
1001 size,
1002 B43legacy_RATE_TO_100KBPS(rate));
1003 /* Write PLCP in two parts and timing for packet transfer */
1004 tmp = le32_to_cpu(plcp.data);
1005 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset,
1006 tmp & 0xFFFF);
1007 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 2,
1008 tmp >> 16);
1009 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 6,
1010 le16_to_cpu(dur));
1011}
1012
1013/* Instead of using custom probe response template, this function
1014 * just patches custom beacon template by:
1015 * 1) Changing packet type
1016 * 2) Patching duration field
1017 * 3) Stripping TIM
1018 */
1019static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
1020 u16 *dest_size, u8 rate)
1021{
1022 const u8 *src_data;
1023 u8 *dest_data;
1024 u16 src_size;
1025 u16 elem_size;
1026 u16 src_pos;
1027 u16 dest_pos;
1028 __le16 dur;
1029 struct ieee80211_hdr *hdr;
1030
1031 B43legacy_WARN_ON(!dev->cached_beacon);
1032 src_size = dev->cached_beacon->len;
1033 src_data = (const u8 *)dev->cached_beacon->data;
1034
1035 if (unlikely(src_size < 0x24)) {
1036 b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: "
1037 "invalid beacon\n");
1038 return NULL;
1039 }
1040
1041 dest_data = kmalloc(src_size, GFP_ATOMIC);
1042 if (unlikely(!dest_data))
1043 return NULL;
1044
1045 /* 0x24 is offset of first variable-len Information-Element
1046 * in beacon frame.
1047 */
1048 memcpy(dest_data, src_data, 0x24);
1049 src_pos = 0x24;
1050 dest_pos = 0x24;
1051 for (; src_pos < src_size - 2; src_pos += elem_size) {
1052 elem_size = src_data[src_pos + 1] + 2;
1053 if (src_data[src_pos] != 0x05) { /* TIM */
1054 memcpy(dest_data + dest_pos, src_data + src_pos,
1055 elem_size);
1056 dest_pos += elem_size;
1057 }
1058 }
1059 *dest_size = dest_pos;
1060 hdr = (struct ieee80211_hdr *)dest_data;
1061
1062 /* Set the frame control. */
1063 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1064 IEEE80211_STYPE_PROBE_RESP);
1065 dur = ieee80211_generic_frame_duration(dev->wl->hw,
1066 dev->wl->if_id,
1067 *dest_size,
1068 B43legacy_RATE_TO_100KBPS(rate));
1069 hdr->duration_id = dur;
1070
1071 return dest_data;
1072}
1073
1074static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
1075 u16 ram_offset,
1076 u16 shm_size_offset, u8 rate)
1077{
1078 u8 *probe_resp_data;
1079 u16 size;
1080
1081 B43legacy_WARN_ON(!dev->cached_beacon);
1082 size = dev->cached_beacon->len;
1083 probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate);
1084 if (unlikely(!probe_resp_data))
1085 return;
1086
1087 /* Looks like PLCP headers plus packet timings are stored for
1088 * all possible basic rates
1089 */
1090 b43legacy_write_probe_resp_plcp(dev, 0x31A, size,
1091 B43legacy_CCK_RATE_1MB);
1092 b43legacy_write_probe_resp_plcp(dev, 0x32C, size,
1093 B43legacy_CCK_RATE_2MB);
1094 b43legacy_write_probe_resp_plcp(dev, 0x33E, size,
1095 B43legacy_CCK_RATE_5MB);
1096 b43legacy_write_probe_resp_plcp(dev, 0x350, size,
1097 B43legacy_CCK_RATE_11MB);
1098
1099 size = min((size_t)size,
1100 0x200 - sizeof(struct b43legacy_plcp_hdr6));
1101 b43legacy_write_template_common(dev, probe_resp_data,
1102 size, ram_offset,
1103 shm_size_offset, rate);
1104 kfree(probe_resp_data);
1105}
1106
1107static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev,
1108 struct sk_buff *beacon)
1109{
1110 if (dev->cached_beacon)
1111 kfree_skb(dev->cached_beacon);
1112 dev->cached_beacon = beacon;
1113
1114 return 0;
1115}
1116
1117static void b43legacy_update_templates(struct b43legacy_wldev *dev)
1118{
1119 u32 status;
1120
1121 B43legacy_WARN_ON(!dev->cached_beacon);
1122
1123 b43legacy_write_beacon_template(dev, 0x68, 0x18,
1124 B43legacy_CCK_RATE_1MB);
1125 b43legacy_write_beacon_template(dev, 0x468, 0x1A,
1126 B43legacy_CCK_RATE_1MB);
1127 b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
1128 B43legacy_CCK_RATE_11MB);
1129
1130 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
1131 status |= 0x03;
1132 b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);
1133}
1134
1135static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
1136 struct sk_buff *beacon)
1137{
1138 int err;
1139
1140 err = b43legacy_refresh_cached_beacon(dev, beacon);
1141 if (unlikely(err))
1142 return;
1143 b43legacy_update_templates(dev);
1144}
1145
1146static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
1147 const u8 *ssid, u8 ssid_len)
1148{
1149 u32 tmp;
1150 u16 i;
1151 u16 len;
1152
1153 len = min((u16)ssid_len, (u16)0x100);
1154 for (i = 0; i < len; i += sizeof(u32)) {
1155 tmp = (u32)(ssid[i + 0]);
1156 if (i + 1 < len)
1157 tmp |= (u32)(ssid[i + 1]) << 8;
1158 if (i + 2 < len)
1159 tmp |= (u32)(ssid[i + 2]) << 16;
1160 if (i + 3 < len)
1161 tmp |= (u32)(ssid[i + 3]) << 24;
1162 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1163 0x380 + i, tmp);
1164 }
1165 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
1166 0x48, len);
1167}
1168
1169static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
1170 u16 beacon_int)
1171{
1172 b43legacy_time_lock(dev);
1173 if (dev->dev->id.revision >= 3)
1174 b43legacy_write32(dev, 0x188, (beacon_int << 16));
1175 else {
1176 b43legacy_write16(dev, 0x606, (beacon_int >> 6));
1177 b43legacy_write16(dev, 0x610, beacon_int);
1178 }
1179 b43legacy_time_unlock(dev);
1180}
1181
1182static void handle_irq_beacon(struct b43legacy_wldev *dev)
1183{
1184 u32 status;
1185
1186 if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
1187 return;
1188
1189 dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
1190 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
1191
1192 if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
1193 /* ACK beacon IRQ. */
1194 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
1195 B43legacy_IRQ_BEACON);
1196 dev->irq_savedstate |= B43legacy_IRQ_BEACON;
1197 if (dev->cached_beacon)
1198 kfree_skb(dev->cached_beacon);
1199 dev->cached_beacon = NULL;
1200 return;
1201 }
1202 if (!(status & 0x1)) {
1203 b43legacy_write_beacon_template(dev, 0x68, 0x18,
1204 B43legacy_CCK_RATE_1MB);
1205 status |= 0x1;
1206 b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
1207 status);
1208 }
1209 if (!(status & 0x2)) {
1210 b43legacy_write_beacon_template(dev, 0x468, 0x1A,
1211 B43legacy_CCK_RATE_1MB);
1212 status |= 0x2;
1213 b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
1214 status);
1215 }
1216}
1217
1218static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
1219{
1220}
1221
1222/* Interrupt handler bottom-half */
1223static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
1224{
1225 u32 reason;
1226 u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
1227 u32 merged_dma_reason = 0;
1228 int i;
1229 int activity = 0;
1230 unsigned long flags;
1231
1232 spin_lock_irqsave(&dev->wl->irq_lock, flags);
1233
1234 B43legacy_WARN_ON(b43legacy_status(dev) <
1235 B43legacy_STAT_INITIALIZED);
1236
1237 reason = dev->irq_reason;
1238 for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
1239 dma_reason[i] = dev->dma_reason[i];
1240 merged_dma_reason |= dma_reason[i];
1241 }
1242
1243 if (unlikely(reason & B43legacy_IRQ_MAC_TXERR))
1244 b43legacyerr(dev->wl, "MAC transmission error\n");
1245
1246 if (unlikely(reason & B43legacy_IRQ_PHY_TXERR))
1247 b43legacyerr(dev->wl, "PHY transmission error\n");
1248
1249 if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK |
1250 B43legacy_DMAIRQ_NONFATALMASK))) {
1251 if (merged_dma_reason & B43legacy_DMAIRQ_FATALMASK) {
1252 b43legacyerr(dev->wl, "Fatal DMA error: "
1253 "0x%08X, 0x%08X, 0x%08X, "
1254 "0x%08X, 0x%08X, 0x%08X\n",
1255 dma_reason[0], dma_reason[1],
1256 dma_reason[2], dma_reason[3],
1257 dma_reason[4], dma_reason[5]);
1258 b43legacy_controller_restart(dev, "DMA error");
1259 mmiowb();
1260 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
1261 return;
1262 }
1263 if (merged_dma_reason & B43legacy_DMAIRQ_NONFATALMASK)
1264 b43legacyerr(dev->wl, "DMA error: "
1265 "0x%08X, 0x%08X, 0x%08X, "
1266 "0x%08X, 0x%08X, 0x%08X\n",
1267 dma_reason[0], dma_reason[1],
1268 dma_reason[2], dma_reason[3],
1269 dma_reason[4], dma_reason[5]);
1270 }
1271
1272 if (unlikely(reason & B43legacy_IRQ_UCODE_DEBUG))
1273 handle_irq_ucode_debug(dev);
1274 if (reason & B43legacy_IRQ_TBTT_INDI)
1275 handle_irq_tbtt_indication(dev);
1276 if (reason & B43legacy_IRQ_ATIM_END)
1277 handle_irq_atim_end(dev);
1278 if (reason & B43legacy_IRQ_BEACON)
1279 handle_irq_beacon(dev);
1280 if (reason & B43legacy_IRQ_PMQ)
1281 handle_irq_pmq(dev);
1282 if (reason & B43legacy_IRQ_TXFIFO_FLUSH_OK)
1283 ;/*TODO*/
1284 if (reason & B43legacy_IRQ_NOISESAMPLE_OK)
1285 handle_irq_noise(dev);
1286
1287 /* Check the DMA reason registers for received data. */
1288 if (dma_reason[0] & B43legacy_DMAIRQ_RX_DONE) {
1289 if (b43legacy_using_pio(dev))
1290 b43legacy_pio_rx(dev->pio.queue0);
1291 else
1292 b43legacy_dma_rx(dev->dma.rx_ring0);
1293 /* We intentionally don't set "activity" to 1, here. */
1294 }
1295 B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE);
1296 B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE);
1297 if (dma_reason[3] & B43legacy_DMAIRQ_RX_DONE) {
1298 if (b43legacy_using_pio(dev))
1299 b43legacy_pio_rx(dev->pio.queue3);
1300 else
1301 b43legacy_dma_rx(dev->dma.rx_ring3);
1302 activity = 1;
1303 }
1304 B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE);
1305 B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE);
1306
1307 if (reason & B43legacy_IRQ_TX_OK) {
1308 handle_irq_transmit_status(dev);
1309 activity = 1;
1310 /* TODO: In AP mode, this also causes sending of powersave
1311 responses. */
1312 }
1313
1314 if (!modparam_noleds)
1315 b43legacy_leds_update(dev, activity);
1316 b43legacy_interrupt_enable(dev, dev->irq_savedstate);
1317 mmiowb();
1318 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
1319}
1320
1321static void pio_irq_workaround(struct b43legacy_wldev *dev,
1322 u16 base, int queueidx)
1323{
1324 u16 rxctl;
1325
1326 rxctl = b43legacy_read16(dev, base + B43legacy_PIO_RXCTL);
1327 if (rxctl & B43legacy_PIO_RXCTL_DATAAVAILABLE)
1328 dev->dma_reason[queueidx] |= B43legacy_DMAIRQ_RX_DONE;
1329 else
1330 dev->dma_reason[queueidx] &= ~B43legacy_DMAIRQ_RX_DONE;
1331}
1332
1333static void b43legacy_interrupt_ack(struct b43legacy_wldev *dev, u32 reason)
1334{
1335 if (b43legacy_using_pio(dev) &&
1336 (dev->dev->id.revision < 3) &&
1337 (!(reason & B43legacy_IRQ_PIO_WORKAROUND))) {
1338 /* Apply a PIO specific workaround to the dma_reasons */
1339 pio_irq_workaround(dev, B43legacy_MMIO_PIO1_BASE, 0);
1340 pio_irq_workaround(dev, B43legacy_MMIO_PIO2_BASE, 1);
1341 pio_irq_workaround(dev, B43legacy_MMIO_PIO3_BASE, 2);
1342 pio_irq_workaround(dev, B43legacy_MMIO_PIO4_BASE, 3);
1343 }
1344
1345 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, reason);
1346
1347 b43legacy_write32(dev, B43legacy_MMIO_DMA0_REASON,
1348 dev->dma_reason[0]);
1349 b43legacy_write32(dev, B43legacy_MMIO_DMA1_REASON,
1350 dev->dma_reason[1]);
1351 b43legacy_write32(dev, B43legacy_MMIO_DMA2_REASON,
1352 dev->dma_reason[2]);
1353 b43legacy_write32(dev, B43legacy_MMIO_DMA3_REASON,
1354 dev->dma_reason[3]);
1355 b43legacy_write32(dev, B43legacy_MMIO_DMA4_REASON,
1356 dev->dma_reason[4]);
1357 b43legacy_write32(dev, B43legacy_MMIO_DMA5_REASON,
1358 dev->dma_reason[5]);
1359}
1360
1361/* Interrupt handler top-half */
1362static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id)
1363{
1364 irqreturn_t ret = IRQ_NONE;
1365 struct b43legacy_wldev *dev = dev_id;
1366 u32 reason;
1367
1368 if (!dev)
1369 return IRQ_NONE;
1370
1371 spin_lock(&dev->wl->irq_lock);
1372
1373 if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
1374 goto out;
1375 reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
1376 if (reason == 0xffffffff) /* shared IRQ */
1377 goto out;
1378 ret = IRQ_HANDLED;
1379 reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
1380 if (!reason)
1381 goto out;
1382
1383 dev->dma_reason[0] = b43legacy_read32(dev,
1384 B43legacy_MMIO_DMA0_REASON)
1385 & 0x0001DC00;
1386 dev->dma_reason[1] = b43legacy_read32(dev,
1387 B43legacy_MMIO_DMA1_REASON)
1388 & 0x0000DC00;
1389 dev->dma_reason[2] = b43legacy_read32(dev,
1390 B43legacy_MMIO_DMA2_REASON)
1391 & 0x0000DC00;
1392 dev->dma_reason[3] = b43legacy_read32(dev,
1393 B43legacy_MMIO_DMA3_REASON)
1394 & 0x0001DC00;
1395 dev->dma_reason[4] = b43legacy_read32(dev,
1396 B43legacy_MMIO_DMA4_REASON)
1397 & 0x0000DC00;
1398 dev->dma_reason[5] = b43legacy_read32(dev,
1399 B43legacy_MMIO_DMA5_REASON)
1400 & 0x0000DC00;
1401
1402 b43legacy_interrupt_ack(dev, reason);
1403 /* disable all IRQs. They are enabled again in the bottom half. */
1404 dev->irq_savedstate = b43legacy_interrupt_disable(dev,
1405 B43legacy_IRQ_ALL);
1406 /* save the reason code and call our bottom half. */
1407 dev->irq_reason = reason;
1408 tasklet_schedule(&dev->isr_tasklet);
1409out:
1410 mmiowb();
1411 spin_unlock(&dev->wl->irq_lock);
1412
1413 return ret;
1414}
1415
1416static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
1417{
1418 release_firmware(dev->fw.ucode);
1419 dev->fw.ucode = NULL;
1420 release_firmware(dev->fw.pcm);
1421 dev->fw.pcm = NULL;
1422 release_firmware(dev->fw.initvals);
1423 dev->fw.initvals = NULL;
1424 release_firmware(dev->fw.initvals_band);
1425 dev->fw.initvals_band = NULL;
1426}
1427
1428static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
1429{
1430 b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
1431 "Drivers/bcm43xx#devicefirmware "
1432 "and download the correct firmware (version 3).\n");
1433}
1434
1435static int do_request_fw(struct b43legacy_wldev *dev,
1436 const char *name,
1437 const struct firmware **fw)
1438{
1439 char path[sizeof(modparam_fwpostfix) + 32];
1440 struct b43legacy_fw_header *hdr;
1441 u32 size;
1442 int err;
1443
1444 if (!name)
1445 return 0;
1446
1447 snprintf(path, ARRAY_SIZE(path),
1448 "b43legacy%s/%s.fw",
1449 modparam_fwpostfix, name);
1450 err = request_firmware(fw, path, dev->dev->dev);
1451 if (err) {
1452 b43legacyerr(dev->wl, "Firmware file \"%s\" not found "
1453 "or load failed.\n", path);
1454 return err;
1455 }
1456 if ((*fw)->size < sizeof(struct b43legacy_fw_header))
1457 goto err_format;
1458 hdr = (struct b43legacy_fw_header *)((*fw)->data);
1459 switch (hdr->type) {
1460 case B43legacy_FW_TYPE_UCODE:
1461 case B43legacy_FW_TYPE_PCM:
1462 size = be32_to_cpu(hdr->size);
1463 if (size != (*fw)->size - sizeof(struct b43legacy_fw_header))
1464 goto err_format;
1465 /* fallthrough */
1466 case B43legacy_FW_TYPE_IV:
1467 if (hdr->ver != 1)
1468 goto err_format;
1469 break;
1470 default:
1471 goto err_format;
1472 }
1473
1474 return err;
1475
1476err_format:
1477 b43legacyerr(dev->wl, "Firmware file \"%s\" format error.\n", path);
1478 return -EPROTO;
1479}
1480
1481static int b43legacy_request_firmware(struct b43legacy_wldev *dev)
1482{
1483 struct b43legacy_firmware *fw = &dev->fw;
1484 const u8 rev = dev->dev->id.revision;
1485 const char *filename;
1486 u32 tmshigh;
1487 int err;
1488
1489 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
1490 if (!fw->ucode) {
1491 if (rev == 2)
1492 filename = "ucode2";
1493 else if (rev == 4)
1494 filename = "ucode4";
1495 else
1496 filename = "ucode5";
1497 err = do_request_fw(dev, filename, &fw->ucode);
1498 if (err)
1499 goto err_load;
1500 }
1501 if (!fw->pcm) {
1502 if (rev < 5)
1503 filename = "pcm4";
1504 else
1505 filename = "pcm5";
1506 err = do_request_fw(dev, filename, &fw->pcm);
1507 if (err)
1508 goto err_load;
1509 }
1510 if (!fw->initvals) {
1511 switch (dev->phy.type) {
1512 case B43legacy_PHYTYPE_G:
1513 if ((rev >= 5) && (rev <= 10))
1514 filename = "b0g0initvals5";
1515 else if (rev == 2 || rev == 4)
1516 filename = "b0g0initvals2";
1517 else
1518 goto err_no_initvals;
1519 break;
1520 default:
1521 goto err_no_initvals;
1522 }
1523 err = do_request_fw(dev, filename, &fw->initvals);
1524 if (err)
1525 goto err_load;
1526 }
1527 if (!fw->initvals_band) {
1528 switch (dev->phy.type) {
1529 case B43legacy_PHYTYPE_G:
1530 if ((rev >= 5) && (rev <= 10))
1531 filename = "b0g0bsinitvals5";
1532 else if (rev >= 11)
1533 filename = NULL;
1534 else if (rev == 2 || rev == 4)
1535 filename = NULL;
1536 else
1537 goto err_no_initvals;
1538 break;
1539 default:
1540 goto err_no_initvals;
1541 }
1542 err = do_request_fw(dev, filename, &fw->initvals_band);
1543 if (err)
1544 goto err_load;
1545 }
1546
1547 return 0;
1548
1549err_load:
1550 b43legacy_print_fw_helptext(dev->wl);
1551 goto error;
1552
1553err_no_initvals:
1554 err = -ENODEV;
1555 b43legacyerr(dev->wl, "No Initial Values firmware file for PHY %u, "
1556 "core rev %u\n", dev->phy.type, rev);
1557 goto error;
1558
1559error:
1560 b43legacy_release_firmware(dev);
1561 return err;
1562}
1563
1564static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
1565{
1566 const size_t hdr_len = sizeof(struct b43legacy_fw_header);
1567 const __be32 *data;
1568 unsigned int i;
1569 unsigned int len;
1570 u16 fwrev;
1571 u16 fwpatch;
1572 u16 fwdate;
1573 u16 fwtime;
1574 u32 tmp;
1575 int err = 0;
1576
1577 /* Upload Microcode. */
1578 data = (__be32 *) (dev->fw.ucode->data + hdr_len);
1579 len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
1580 b43legacy_shm_control_word(dev,
1581 B43legacy_SHM_UCODE |
1582 B43legacy_SHM_AUTOINC_W,
1583 0x0000);
1584 for (i = 0; i < len; i++) {
1585 b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
1586 be32_to_cpu(data[i]));
1587 udelay(10);
1588 }
1589
1590 if (dev->fw.pcm) {
1591 /* Upload PCM data. */
1592 data = (__be32 *) (dev->fw.pcm->data + hdr_len);
1593 len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
1594 b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EA);
1595 b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, 0x00004000);
1596 /* No need for autoinc bit in SHM_HW */
1597 b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EB);
1598 for (i = 0; i < len; i++) {
1599 b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
1600 be32_to_cpu(data[i]));
1601 udelay(10);
1602 }
1603 }
1604
1605 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
1606 B43legacy_IRQ_ALL);
1607 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402);
1608
1609 /* Wait for the microcode to load and respond */
1610 i = 0;
1611 while (1) {
1612 tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
1613 if (tmp == B43legacy_IRQ_MAC_SUSPENDED)
1614 break;
1615 i++;
1616 if (i >= B43legacy_IRQWAIT_MAX_RETRIES) {
1617 b43legacyerr(dev->wl, "Microcode not responding\n");
1618 b43legacy_print_fw_helptext(dev->wl);
1619 err = -ENODEV;
1620 goto out;
1621 }
1622 udelay(10);
1623 }
1624 /* dummy read follows */
1625 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
1626
1627 /* Get and check the revisions. */
1628 fwrev = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1629 B43legacy_SHM_SH_UCODEREV);
1630 fwpatch = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1631 B43legacy_SHM_SH_UCODEPATCH);
1632 fwdate = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1633 B43legacy_SHM_SH_UCODEDATE);
1634 fwtime = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1635 B43legacy_SHM_SH_UCODETIME);
1636
1637 if (fwrev > 0x128) {
1638 b43legacyerr(dev->wl, "YOU ARE TRYING TO LOAD V4 FIRMWARE."
1639 " Only firmware from binary drivers version 3.x"
1640 " is supported. You must change your firmware"
1641 " files.\n");
1642 b43legacy_print_fw_helptext(dev->wl);
1643 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0);
1644 err = -EOPNOTSUPP;
1645 goto out;
1646 }
1647 b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
1648 "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
1649 (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
1650 (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
1651
1652 dev->fw.rev = fwrev;
1653 dev->fw.patch = fwpatch;
1654
1655out:
1656 return err;
1657}
1658
1659static int b43legacy_write_initvals(struct b43legacy_wldev *dev,
1660 const struct b43legacy_iv *ivals,
1661 size_t count,
1662 size_t array_size)
1663{
1664 const struct b43legacy_iv *iv;
1665 u16 offset;
1666 size_t i;
1667 bool bit32;
1668
1669 BUILD_BUG_ON(sizeof(struct b43legacy_iv) != 6);
1670 iv = ivals;
1671 for (i = 0; i < count; i++) {
1672 if (array_size < sizeof(iv->offset_size))
1673 goto err_format;
1674 array_size -= sizeof(iv->offset_size);
1675 offset = be16_to_cpu(iv->offset_size);
1676 bit32 = !!(offset & B43legacy_IV_32BIT);
1677 offset &= B43legacy_IV_OFFSET_MASK;
1678 if (offset >= 0x1000)
1679 goto err_format;
1680 if (bit32) {
1681 u32 value;
1682
1683 if (array_size < sizeof(iv->data.d32))
1684 goto err_format;
1685 array_size -= sizeof(iv->data.d32);
1686
1687 value = be32_to_cpu(get_unaligned(&iv->data.d32));
1688 b43legacy_write32(dev, offset, value);
1689
1690 iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
1691 sizeof(__be16) +
1692 sizeof(__be32));
1693 } else {
1694 u16 value;
1695
1696 if (array_size < sizeof(iv->data.d16))
1697 goto err_format;
1698 array_size -= sizeof(iv->data.d16);
1699
1700 value = be16_to_cpu(iv->data.d16);
1701 b43legacy_write16(dev, offset, value);
1702
1703 iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
1704 sizeof(__be16) +
1705 sizeof(__be16));
1706 }
1707 }
1708 if (array_size)
1709 goto err_format;
1710
1711 return 0;
1712
1713err_format:
1714 b43legacyerr(dev->wl, "Initial Values Firmware file-format error.\n");
1715 b43legacy_print_fw_helptext(dev->wl);
1716
1717 return -EPROTO;
1718}
1719
1720static int b43legacy_upload_initvals(struct b43legacy_wldev *dev)
1721{
1722 const size_t hdr_len = sizeof(struct b43legacy_fw_header);
1723 const struct b43legacy_fw_header *hdr;
1724 struct b43legacy_firmware *fw = &dev->fw;
1725 const struct b43legacy_iv *ivals;
1726 size_t count;
1727 int err;
1728
1729 hdr = (const struct b43legacy_fw_header *)(fw->initvals->data);
1730 ivals = (const struct b43legacy_iv *)(fw->initvals->data + hdr_len);
1731 count = be32_to_cpu(hdr->size);
1732 err = b43legacy_write_initvals(dev, ivals, count,
1733 fw->initvals->size - hdr_len);
1734 if (err)
1735 goto out;
1736 if (fw->initvals_band) {
1737 hdr = (const struct b43legacy_fw_header *)
1738 (fw->initvals_band->data);
1739 ivals = (const struct b43legacy_iv *)(fw->initvals_band->data
1740 + hdr_len);
1741 count = be32_to_cpu(hdr->size);
1742 err = b43legacy_write_initvals(dev, ivals, count,
1743 fw->initvals_band->size - hdr_len);
1744 if (err)
1745 goto out;
1746 }
1747out:
1748
1749 return err;
1750}
1751
1752/* Initialize the GPIOs
1753 * http://bcm-specs.sipsolutions.net/GPIO
1754 */
1755static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
1756{
1757 struct ssb_bus *bus = dev->dev->bus;
1758 struct ssb_device *gpiodev, *pcidev = NULL;
1759 u32 mask;
1760 u32 set;
1761
1762 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
1763 b43legacy_read32(dev,
1764 B43legacy_MMIO_STATUS_BITFIELD)
1765 & 0xFFFF3FFF);
1766
1767 b43legacy_leds_switch_all(dev, 0);
1768 b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
1769 b43legacy_read16(dev,
1770 B43legacy_MMIO_GPIO_MASK)
1771 | 0x000F);
1772
1773 mask = 0x0000001F;
1774 set = 0x0000000F;
1775 if (dev->dev->bus->chip_id == 0x4301) {
1776 mask |= 0x0060;
1777 set |= 0x0060;
1778 }
1779 if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) {
1780 b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
1781 b43legacy_read16(dev,
1782 B43legacy_MMIO_GPIO_MASK)
1783 | 0x0200);
1784 mask |= 0x0200;
1785 set |= 0x0200;
1786 }
1787 if (dev->dev->id.revision >= 2)
1788 mask |= 0x0010; /* FIXME: This is redundant. */
1789
1790#ifdef CONFIG_SSB_DRIVER_PCICORE
1791 pcidev = bus->pcicore.dev;
1792#endif
1793 gpiodev = bus->chipco.dev ? : pcidev;
1794 if (!gpiodev)
1795 return 0;
1796 ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
1797 (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
1798 & mask) | set);
1799
1800 return 0;
1801}
1802
1803/* Turn off all GPIO stuff. Call this on module unload, for example. */
1804static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev)
1805{
1806 struct ssb_bus *bus = dev->dev->bus;
1807 struct ssb_device *gpiodev, *pcidev = NULL;
1808
1809#ifdef CONFIG_SSB_DRIVER_PCICORE
1810 pcidev = bus->pcicore.dev;
1811#endif
1812 gpiodev = bus->chipco.dev ? : pcidev;
1813 if (!gpiodev)
1814 return;
1815 ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, 0);
1816}
1817
1818/* http://bcm-specs.sipsolutions.net/EnableMac */
1819void b43legacy_mac_enable(struct b43legacy_wldev *dev)
1820{
1821 dev->mac_suspended--;
1822 B43legacy_WARN_ON(dev->mac_suspended < 0);
1823 if (dev->mac_suspended == 0) {
1824 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
1825 b43legacy_read32(dev,
1826 B43legacy_MMIO_STATUS_BITFIELD)
1827 | B43legacy_SBF_MAC_ENABLED);
1828 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
1829 B43legacy_IRQ_MAC_SUSPENDED);
1830 /* the next two are dummy reads */
1831 b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
1832 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
1833 b43legacy_power_saving_ctl_bits(dev, -1, -1);
1834 }
1835}
1836
1837/* http://bcm-specs.sipsolutions.net/SuspendMAC */
1838void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
1839{
1840 int i;
1841 u32 tmp;
1842
1843 B43legacy_WARN_ON(dev->mac_suspended < 0);
1844 if (dev->mac_suspended == 0) {
1845 b43legacy_power_saving_ctl_bits(dev, -1, 1);
1846 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
1847 b43legacy_read32(dev,
1848 B43legacy_MMIO_STATUS_BITFIELD)
1849 & ~B43legacy_SBF_MAC_ENABLED);
1850 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
1851 for (i = 10000; i; i--) {
1852 tmp = b43legacy_read32(dev,
1853 B43legacy_MMIO_GEN_IRQ_REASON);
1854 if (tmp & B43legacy_IRQ_MAC_SUSPENDED)
1855 goto out;
1856 udelay(1);
1857 }
1858 b43legacyerr(dev->wl, "MAC suspend failed\n");
1859 }
1860out:
1861 dev->mac_suspended++;
1862}
1863
1864static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
1865{
1866 struct b43legacy_wl *wl = dev->wl;
1867 u32 ctl;
1868 u16 cfp_pretbtt;
1869
1870 ctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
1871 /* Reset status to STA infrastructure mode. */
1872 ctl &= ~B43legacy_MACCTL_AP;
1873 ctl &= ~B43legacy_MACCTL_KEEP_CTL;
1874 ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP;
1875 ctl &= ~B43legacy_MACCTL_KEEP_BAD;
1876 ctl &= ~B43legacy_MACCTL_PROMISC;
1877 ctl |= B43legacy_MACCTL_INFRA;
1878
1879 if (wl->operating) {
1880 switch (wl->if_type) {
1881 case IEEE80211_IF_TYPE_AP:
1882 ctl |= B43legacy_MACCTL_AP;
1883 break;
1884 case IEEE80211_IF_TYPE_IBSS:
1885 ctl &= ~B43legacy_MACCTL_INFRA;
1886 break;
1887 case IEEE80211_IF_TYPE_STA:
1888 case IEEE80211_IF_TYPE_MNTR:
1889 case IEEE80211_IF_TYPE_WDS:
1890 break;
1891 default:
1892 b43legacyerr(wl, "Improper value of %d for"
1893 " wl->if_type\n", wl->if_type);
1894 }
1895 }
1896 if (wl->monitor) {
1897 ctl |= B43legacy_MACCTL_KEEP_CTL;
1898 if (modparam_mon_keep_bad)
1899 ctl |= B43legacy_MACCTL_KEEP_BAD;
1900 if (modparam_mon_keep_badplcp)
1901 ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
1902 }
1903 if (wl->promisc)
1904 ctl |= B43legacy_MACCTL_PROMISC;
1905 /* Workaround: On old hardware the HW-MAC-address-filter
1906 * doesn't work properly, so always run promisc in filter
1907 * it in software. */
1908 if (dev->dev->id.revision <= 4)
1909 ctl |= B43legacy_MACCTL_PROMISC;
1910
1911 b43legacy_write32(dev, B43legacy_MMIO_MACCTL, ctl);
1912
1913 cfp_pretbtt = 2;
1914 if ((ctl & B43legacy_MACCTL_INFRA) &&
1915 !(ctl & B43legacy_MACCTL_AP)) {
1916 if (dev->dev->bus->chip_id == 0x4306 &&
1917 dev->dev->bus->chip_rev == 3)
1918 cfp_pretbtt = 100;
1919 else
1920 cfp_pretbtt = 50;
1921 }
1922 b43legacy_write16(dev, 0x612, cfp_pretbtt);
1923}
1924
1925static void b43legacy_rate_memory_write(struct b43legacy_wldev *dev,
1926 u16 rate,
1927 int is_ofdm)
1928{
1929 u16 offset;
1930
1931 if (is_ofdm) {
1932 offset = 0x480;
1933 offset += (b43legacy_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
1934 } else {
1935 offset = 0x4C0;
1936 offset += (b43legacy_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
1937 }
1938 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, offset + 0x20,
1939 b43legacy_shm_read16(dev,
1940 B43legacy_SHM_SHARED, offset));
1941}
1942
1943static void b43legacy_rate_memory_init(struct b43legacy_wldev *dev)
1944{
1945 switch (dev->phy.type) {
1946 case B43legacy_PHYTYPE_G:
1947 b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_6MB, 1);
1948 b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_12MB, 1);
1949 b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_18MB, 1);
1950 b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_24MB, 1);
1951 b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_36MB, 1);
1952 b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_48MB, 1);
1953 b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_54MB, 1);
1954 /* fallthrough */
1955 case B43legacy_PHYTYPE_B:
1956 b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_1MB, 0);
1957 b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_2MB, 0);
1958 b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_5MB, 0);
1959 b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_11MB, 0);
1960 break;
1961 default:
1962 B43legacy_BUG_ON(1);
1963 }
1964}
1965
1966/* Set the TX-Antenna for management frames sent by firmware. */
1967static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
1968 int antenna)
1969{
1970 u16 ant = 0;
1971 u16 tmp;
1972
1973 switch (antenna) {
1974 case B43legacy_ANTENNA0:
1975 ant |= B43legacy_TX4_PHY_ANT0;
1976 break;
1977 case B43legacy_ANTENNA1:
1978 ant |= B43legacy_TX4_PHY_ANT1;
1979 break;
1980 case B43legacy_ANTENNA_AUTO:
1981 ant |= B43legacy_TX4_PHY_ANTLAST;
1982 break;
1983 default:
1984 B43legacy_BUG_ON(1);
1985 }
1986
1987 /* FIXME We also need to set the other flags of the PHY control
1988 * field somewhere. */
1989
1990 /* For Beacons */
1991 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1992 B43legacy_SHM_SH_BEACPHYCTL);
1993 tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
1994 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
1995 B43legacy_SHM_SH_BEACPHYCTL, tmp);
1996 /* For ACK/CTS */
1997 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1998 B43legacy_SHM_SH_ACKCTSPHYCTL);
1999 tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
2000 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
2001 B43legacy_SHM_SH_ACKCTSPHYCTL, tmp);
2002 /* For Probe Resposes */
2003 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
2004 B43legacy_SHM_SH_PRPHYCTL);
2005 tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
2006 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
2007 B43legacy_SHM_SH_PRPHYCTL, tmp);
2008}
2009
2010/* This is the opposite of b43legacy_chip_init() */
2011static void b43legacy_chip_exit(struct b43legacy_wldev *dev)
2012{
2013 b43legacy_radio_turn_off(dev);
2014 if (!modparam_noleds)
2015 b43legacy_leds_exit(dev);
2016 b43legacy_gpio_cleanup(dev);
2017 /* firmware is released later */
2018}
2019
2020/* Initialize the chip
2021 * http://bcm-specs.sipsolutions.net/ChipInit
2022 */
2023static int b43legacy_chip_init(struct b43legacy_wldev *dev)
2024{
2025 struct b43legacy_phy *phy = &dev->phy;
2026 int err;
2027 int tmp;
2028 u32 value32;
2029 u16 value16;
2030
2031 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
2032 B43legacy_SBF_CORE_READY
2033 | B43legacy_SBF_400);
2034
2035 err = b43legacy_request_firmware(dev);
2036 if (err)
2037 goto out;
2038 err = b43legacy_upload_microcode(dev);
2039 if (err)
2040 goto out; /* firmware is released later */
2041
2042 err = b43legacy_gpio_init(dev);
2043 if (err)
2044 goto out; /* firmware is released later */
2045 err = b43legacy_upload_initvals(dev);
2046 if (err)
2047 goto err_gpio_cleanup;
2048 b43legacy_radio_turn_on(dev);
2049 dev->radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
2050 b43legacyinfo(dev->wl, "Radio %s by hardware\n",
2051 (dev->radio_hw_enable == 0) ? "disabled" : "enabled");
2052
2053 b43legacy_write16(dev, 0x03E6, 0x0000);
2054 err = b43legacy_phy_init(dev);
2055 if (err)
2056 goto err_radio_off;
2057
2058 /* Select initial Interference Mitigation. */
2059 tmp = phy->interfmode;
2060 phy->interfmode = B43legacy_INTERFMODE_NONE;
2061 b43legacy_radio_set_interference_mitigation(dev, tmp);
2062
2063 b43legacy_phy_set_antenna_diversity(dev);
2064 b43legacy_mgmtframe_txantenna(dev, B43legacy_ANTENNA_DEFAULT);
2065
2066 if (phy->type == B43legacy_PHYTYPE_B) {
2067 value16 = b43legacy_read16(dev, 0x005E);
2068 value16 |= 0x0004;
2069 b43legacy_write16(dev, 0x005E, value16);
2070 }
2071 b43legacy_write32(dev, 0x0100, 0x01000000);
2072 if (dev->dev->id.revision < 5)
2073 b43legacy_write32(dev, 0x010C, 0x01000000);
2074
2075 value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
2076 value32 &= ~B43legacy_SBF_MODE_NOTADHOC;
2077 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
2078 value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
2079 value32 |= B43legacy_SBF_MODE_NOTADHOC;
2080 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
2081
2082 value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
2083 value32 |= 0x100000;
2084 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
2085
2086 if (b43legacy_using_pio(dev)) {
2087 b43legacy_write32(dev, 0x0210, 0x00000100);
2088 b43legacy_write32(dev, 0x0230, 0x00000100);
2089 b43legacy_write32(dev, 0x0250, 0x00000100);
2090 b43legacy_write32(dev, 0x0270, 0x00000100);
2091 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0034,
2092 0x0000);
2093 }
2094
2095 /* Probe Response Timeout value */
2096 /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
2097 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0074, 0x0000);
2098
2099 /* Initially set the wireless operation mode. */
2100 b43legacy_adjust_opmode(dev);
2101
2102 if (dev->dev->id.revision < 3) {
2103 b43legacy_write16(dev, 0x060E, 0x0000);
2104 b43legacy_write16(dev, 0x0610, 0x8000);
2105 b43legacy_write16(dev, 0x0604, 0x0000);
2106 b43legacy_write16(dev, 0x0606, 0x0200);
2107 } else {
2108 b43legacy_write32(dev, 0x0188, 0x80000000);
2109 b43legacy_write32(dev, 0x018C, 0x02000000);
2110 }
2111 b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, 0x00004000);
2112 b43legacy_write32(dev, B43legacy_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
2113 b43legacy_write32(dev, B43legacy_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
2114 b43legacy_write32(dev, B43legacy_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
2115 b43legacy_write32(dev, B43legacy_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
2116 b43legacy_write32(dev, B43legacy_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
2117 b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
2118
2119 value32 = ssb_read32(dev->dev, SSB_TMSLOW);
2120 value32 |= 0x00100000;
2121 ssb_write32(dev->dev, SSB_TMSLOW, value32);
2122
2123 b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
2124 dev->dev->bus->chipco.fast_pwrup_delay);
2125
2126 B43legacy_WARN_ON(err != 0);
2127 b43legacydbg(dev->wl, "Chip initialized\n");
2128out:
2129 return err;
2130
2131err_radio_off:
2132 b43legacy_radio_turn_off(dev);
2133err_gpio_cleanup:
2134 b43legacy_gpio_cleanup(dev);
2135 goto out;
2136}
2137
2138static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev)
2139{
2140 struct b43legacy_phy *phy = &dev->phy;
2141
2142 if (phy->type != B43legacy_PHYTYPE_G || phy->rev < 2)
2143 return;
2144
2145 b43legacy_mac_suspend(dev);
2146 b43legacy_phy_lo_g_measure(dev);
2147 b43legacy_mac_enable(dev);
2148}
2149
2150static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev)
2151{
2152 b43legacy_phy_lo_mark_all_unused(dev);
2153 if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
2154 b43legacy_mac_suspend(dev);
2155 b43legacy_calc_nrssi_slope(dev);
2156 b43legacy_mac_enable(dev);
2157 }
2158}
2159
2160static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev)
2161{
2162 /* Update device statistics. */
2163 b43legacy_calculate_link_quality(dev);
2164}
2165
2166static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev)
2167{
2168 b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */
2169}
2170
2171static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev)
2172{
2173 int radio_hw_enable;
2174
2175 /* check if radio hardware enabled status changed */
2176 radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
2177 if (unlikely(dev->radio_hw_enable != radio_hw_enable)) {
2178 dev->radio_hw_enable = radio_hw_enable;
2179 b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n",
2180 (radio_hw_enable == 0) ? "disabled" : "enabled");
2181 b43legacy_leds_update(dev, 0);
2182 }
2183}
2184
2185static void do_periodic_work(struct b43legacy_wldev *dev)
2186{
2187 unsigned int state;
2188
2189 state = dev->periodic_state;
2190 if (state % 120 == 0)
2191 b43legacy_periodic_every120sec(dev);
2192 if (state % 60 == 0)
2193 b43legacy_periodic_every60sec(dev);
2194 if (state % 30 == 0)
2195 b43legacy_periodic_every30sec(dev);
2196 if (state % 15 == 0)
2197 b43legacy_periodic_every15sec(dev);
2198 b43legacy_periodic_every1sec(dev);
2199}
2200
2201/* Estimate a "Badness" value based on the periodic work
2202 * state-machine state. "Badness" is worse (bigger), if the
2203 * periodic work will take longer.
2204 */
2205static int estimate_periodic_work_badness(unsigned int state)
2206{
2207 int badness = 0;
2208
2209 if (state % 120 == 0) /* every 120 sec */
2210 badness += 10;
2211 if (state % 60 == 0) /* every 60 sec */
2212 badness += 5;
2213 if (state % 30 == 0) /* every 30 sec */
2214 badness += 1;
2215 if (state % 15 == 0) /* every 15 sec */
2216 badness += 1;
2217
2218#define BADNESS_LIMIT 4
2219 return badness;
2220}
2221
2222static void b43legacy_periodic_work_handler(struct work_struct *work)
2223{
2224 struct b43legacy_wldev *dev =
2225 container_of(work, struct b43legacy_wldev,
2226 periodic_work.work);
2227 unsigned long flags;
2228 unsigned long delay;
2229 u32 savedirqs = 0;
2230 int badness;
2231
2232 mutex_lock(&dev->wl->mutex);
2233
2234 if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED))
2235 goto out;
2236 if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP))
2237 goto out_requeue;
2238
2239 badness = estimate_periodic_work_badness(dev->periodic_state);
2240 if (badness > BADNESS_LIMIT) {
2241 spin_lock_irqsave(&dev->wl->irq_lock, flags);
2242 /* Suspend TX as we don't want to transmit packets while
2243 * we recalibrate the hardware. */
2244 b43legacy_tx_suspend(dev);
2245 savedirqs = b43legacy_interrupt_disable(dev,
2246 B43legacy_IRQ_ALL);
2247 /* Periodic work will take a long time, so we want it to
2248 * be preemtible and release the spinlock. */
2249 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
2250 b43legacy_synchronize_irq(dev);
2251
2252 do_periodic_work(dev);
2253
2254 spin_lock_irqsave(&dev->wl->irq_lock, flags);
2255 b43legacy_interrupt_enable(dev, savedirqs);
2256 b43legacy_tx_resume(dev);
2257 mmiowb();
2258 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
2259 } else {
2260 /* Take the global driver lock. This will lock any operation. */
2261 spin_lock_irqsave(&dev->wl->irq_lock, flags);
2262
2263 do_periodic_work(dev);
2264
2265 mmiowb();
2266 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
2267 }
2268 dev->periodic_state++;
2269out_requeue:
2270 if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST))
2271 delay = msecs_to_jiffies(50);
2272 else
2273 delay = round_jiffies(HZ);
2274 queue_delayed_work(dev->wl->hw->workqueue,
2275 &dev->periodic_work, delay);
2276out:
2277 mutex_unlock(&dev->wl->mutex);
2278}
2279
2280static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
2281{
2282 struct delayed_work *work = &dev->periodic_work;
2283
2284 dev->periodic_state = 0;
2285 INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler);
2286 queue_delayed_work(dev->wl->hw->workqueue, work, 0);
2287}
2288
2289/* Validate access to the chip (SHM) */
2290static int b43legacy_validate_chipaccess(struct b43legacy_wldev *dev)
2291{
2292 u32 value;
2293 u32 shm_backup;
2294
2295 shm_backup = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0);
2296 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0xAA5555AA);
2297 if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
2298 0xAA5555AA)
2299 goto error;
2300 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0x55AAAA55);
2301 if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
2302 0x55AAAA55)
2303 goto error;
2304 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, shm_backup);
2305
2306 value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
2307 if ((value | B43legacy_MACCTL_GMODE) !=
2308 (B43legacy_MACCTL_GMODE | B43legacy_MACCTL_IHR_ENABLED))
2309 goto error;
2310
2311 value = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
2312 if (value)
2313 goto error;
2314
2315 return 0;
2316error:
2317 b43legacyerr(dev->wl, "Failed to validate the chipaccess\n");
2318 return -ENODEV;
2319}
2320
2321static void b43legacy_security_init(struct b43legacy_wldev *dev)
2322{
2323 dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
2324 B43legacy_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
2325 dev->ktp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
2326 0x0056);
2327 /* KTP is a word address, but we address SHM bytewise.
2328 * So multiply by two.
2329 */
2330 dev->ktp *= 2;
2331 if (dev->dev->id.revision >= 5)
2332 /* Number of RCMTA address slots */
2333 b43legacy_write16(dev, B43legacy_MMIO_RCMTA_COUNT,
2334 dev->max_nr_keys - 8);
2335}
2336
2337static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
2338{
2339 struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv;
2340 unsigned long flags;
2341
2342 /* Don't take wl->mutex here, as it could deadlock with
2343 * hwrng internal locking. It's not needed to take
2344 * wl->mutex here, anyway. */
2345
2346 spin_lock_irqsave(&wl->irq_lock, flags);
2347 *data = b43legacy_read16(wl->current_dev, B43legacy_MMIO_RNG);
2348 spin_unlock_irqrestore(&wl->irq_lock, flags);
2349
2350 return (sizeof(u16));
2351}
2352
2353static void b43legacy_rng_exit(struct b43legacy_wl *wl)
2354{
2355 if (wl->rng_initialized)
2356 hwrng_unregister(&wl->rng);
2357}
2358
2359static int b43legacy_rng_init(struct b43legacy_wl *wl)
2360{
2361 int err;
2362
2363 snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
2364 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
2365 wl->rng.name = wl->rng_name;
2366 wl->rng.data_read = b43legacy_rng_read;
2367 wl->rng.priv = (unsigned long)wl;
2368 wl->rng_initialized = 1;
2369 err = hwrng_register(&wl->rng);
2370 if (err) {
2371 wl->rng_initialized = 0;
2372 b43legacyerr(wl, "Failed to register the random "
2373 "number generator (%d)\n", err);
2374 }
2375
2376 return err;
2377}
2378
2379static int b43legacy_tx(struct ieee80211_hw *hw,
2380 struct sk_buff *skb,
2381 struct ieee80211_tx_control *ctl)
2382{
2383 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2384 struct b43legacy_wldev *dev = wl->current_dev;
2385 int err = -ENODEV;
2386 unsigned long flags;
2387
2388 if (unlikely(!dev))
2389 goto out;
2390 if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
2391 goto out;
2392 /* DMA-TX is done without a global lock. */
2393 if (b43legacy_using_pio(dev)) {
2394 spin_lock_irqsave(&wl->irq_lock, flags);
2395 err = b43legacy_pio_tx(dev, skb, ctl);
2396 spin_unlock_irqrestore(&wl->irq_lock, flags);
2397 } else
2398 err = b43legacy_dma_tx(dev, skb, ctl);
2399out:
2400 if (unlikely(err))
2401 return NETDEV_TX_BUSY;
2402 return NETDEV_TX_OK;
2403}
2404
2405static int b43legacy_conf_tx(struct ieee80211_hw *hw,
2406 int queue,
2407 const struct ieee80211_tx_queue_params *params)
2408{
2409 return 0;
2410}
2411
2412static int b43legacy_get_tx_stats(struct ieee80211_hw *hw,
2413 struct ieee80211_tx_queue_stats *stats)
2414{
2415 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2416 struct b43legacy_wldev *dev = wl->current_dev;
2417 unsigned long flags;
2418 int err = -ENODEV;
2419
2420 if (!dev)
2421 goto out;
2422 spin_lock_irqsave(&wl->irq_lock, flags);
2423 if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) {
2424 if (b43legacy_using_pio(dev))
2425 b43legacy_pio_get_tx_stats(dev, stats);
2426 else
2427 b43legacy_dma_get_tx_stats(dev, stats);
2428 err = 0;
2429 }
2430 spin_unlock_irqrestore(&wl->irq_lock, flags);
2431out:
2432 return err;
2433}
2434
2435static int b43legacy_get_stats(struct ieee80211_hw *hw,
2436 struct ieee80211_low_level_stats *stats)
2437{
2438 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2439 unsigned long flags;
2440
2441 spin_lock_irqsave(&wl->irq_lock, flags);
2442 memcpy(stats, &wl->ieee_stats, sizeof(*stats));
2443 spin_unlock_irqrestore(&wl->irq_lock, flags);
2444
2445 return 0;
2446}
2447
2448static const char *phymode_to_string(unsigned int phymode)
2449{
2450 switch (phymode) {
2451 case B43legacy_PHYMODE_B:
2452 return "B";
2453 case B43legacy_PHYMODE_G:
2454 return "G";
2455 default:
2456 B43legacy_BUG_ON(1);
2457 }
2458 return "";
2459}
2460
2461static int find_wldev_for_phymode(struct b43legacy_wl *wl,
2462 unsigned int phymode,
2463 struct b43legacy_wldev **dev,
2464 bool *gmode)
2465{
2466 struct b43legacy_wldev *d;
2467
2468 list_for_each_entry(d, &wl->devlist, list) {
2469 if (d->phy.possible_phymodes & phymode) {
2470 /* Ok, this device supports the PHY-mode.
2471 * Set the gmode bit. */
2472 *gmode = 1;
2473 *dev = d;
2474
2475 return 0;
2476 }
2477 }
2478
2479 return -ESRCH;
2480}
2481
2482static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev)
2483{
2484 struct ssb_device *sdev = dev->dev;
2485 u32 tmslow;
2486
2487 tmslow = ssb_read32(sdev, SSB_TMSLOW);
2488 tmslow &= ~B43legacy_TMSLOW_GMODE;
2489 tmslow |= B43legacy_TMSLOW_PHYRESET;
2490 tmslow |= SSB_TMSLOW_FGC;
2491 ssb_write32(sdev, SSB_TMSLOW, tmslow);
2492 msleep(1);
2493
2494 tmslow = ssb_read32(sdev, SSB_TMSLOW);
2495 tmslow &= ~SSB_TMSLOW_FGC;
2496 tmslow |= B43legacy_TMSLOW_PHYRESET;
2497 ssb_write32(sdev, SSB_TMSLOW, tmslow);
2498 msleep(1);
2499}
2500
2501/* Expects wl->mutex locked */
2502static int b43legacy_switch_phymode(struct b43legacy_wl *wl,
2503 unsigned int new_mode)
2504{
2505 struct b43legacy_wldev *up_dev;
2506 struct b43legacy_wldev *down_dev;
2507 int err;
2508 bool gmode = 0;
2509 int prev_status;
2510
2511 err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
2512 if (err) {
2513 b43legacyerr(wl, "Could not find a device for %s-PHY mode\n",
2514 phymode_to_string(new_mode));
2515 return err;
2516 }
2517 if ((up_dev == wl->current_dev) &&
2518 (!!wl->current_dev->phy.gmode == !!gmode))
2519 /* This device is already running. */
2520 return 0;
2521 b43legacydbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
2522 phymode_to_string(new_mode));
2523 down_dev = wl->current_dev;
2524
2525 prev_status = b43legacy_status(down_dev);
2526 /* Shutdown the currently running core. */
2527 if (prev_status >= B43legacy_STAT_STARTED)
2528 b43legacy_wireless_core_stop(down_dev);
2529 if (prev_status >= B43legacy_STAT_INITIALIZED)
2530 b43legacy_wireless_core_exit(down_dev);
2531
2532 if (down_dev != up_dev)
2533 /* We switch to a different core, so we put PHY into
2534 * RESET on the old core. */
2535 b43legacy_put_phy_into_reset(down_dev);
2536
2537 /* Now start the new core. */
2538 up_dev->phy.gmode = gmode;
2539 if (prev_status >= B43legacy_STAT_INITIALIZED) {
2540 err = b43legacy_wireless_core_init(up_dev);
2541 if (err) {
2542 b43legacyerr(wl, "Fatal: Could not initialize device"
2543 " for newly selected %s-PHY mode\n",
2544 phymode_to_string(new_mode));
2545 goto init_failure;
2546 }
2547 }
2548 if (prev_status >= B43legacy_STAT_STARTED) {
2549 err = b43legacy_wireless_core_start(up_dev);
2550 if (err) {
2551 b43legacyerr(wl, "Fatal: Coult not start device for "
2552 "newly selected %s-PHY mode\n",
2553 phymode_to_string(new_mode));
2554 b43legacy_wireless_core_exit(up_dev);
2555 goto init_failure;
2556 }
2557 }
2558 B43legacy_WARN_ON(b43legacy_status(up_dev) != prev_status);
2559
2560 b43legacy_shm_write32(up_dev, B43legacy_SHM_SHARED, 0x003E, 0);
2561
2562 wl->current_dev = up_dev;
2563
2564 return 0;
2565init_failure:
2566 /* Whoops, failed to init the new core. No core is operating now. */
2567 wl->current_dev = NULL;
2568 return err;
2569}
2570
2571static int b43legacy_antenna_from_ieee80211(u8 antenna)
2572{
2573 switch (antenna) {
2574 case 0: /* default/diversity */
2575 return B43legacy_ANTENNA_DEFAULT;
2576 case 1: /* Antenna 0 */
2577 return B43legacy_ANTENNA0;
2578 case 2: /* Antenna 1 */
2579 return B43legacy_ANTENNA1;
2580 default:
2581 return B43legacy_ANTENNA_DEFAULT;
2582 }
2583}
2584
2585static int b43legacy_dev_config(struct ieee80211_hw *hw,
2586 struct ieee80211_conf *conf)
2587{
2588 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2589 struct b43legacy_wldev *dev;
2590 struct b43legacy_phy *phy;
2591 unsigned long flags;
2592 unsigned int new_phymode = 0xFFFF;
2593 int antenna_tx;
2594 int antenna_rx;
2595 int err = 0;
2596 u32 savedirqs;
2597
2598 antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx);
2599 antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
2600
2601 mutex_lock(&wl->mutex);
2602
2603 /* Switch the PHY mode (if necessary). */
2604 switch (conf->phymode) {
2605 case MODE_IEEE80211B:
2606 new_phymode = B43legacy_PHYMODE_B;
2607 break;
2608 case MODE_IEEE80211G:
2609 new_phymode = B43legacy_PHYMODE_G;
2610 break;
2611 default:
2612 B43legacy_WARN_ON(1);
2613 }
2614 err = b43legacy_switch_phymode(wl, new_phymode);
2615 if (err)
2616 goto out_unlock_mutex;
2617 dev = wl->current_dev;
2618 phy = &dev->phy;
2619
2620 /* Disable IRQs while reconfiguring the device.
2621 * This makes it possible to drop the spinlock throughout
2622 * the reconfiguration process. */
2623 spin_lock_irqsave(&wl->irq_lock, flags);
2624 if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
2625 spin_unlock_irqrestore(&wl->irq_lock, flags);
2626 goto out_unlock_mutex;
2627 }
2628 savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
2629 spin_unlock_irqrestore(&wl->irq_lock, flags);
2630 b43legacy_synchronize_irq(dev);
2631
2632 /* Switch to the requested channel.
2633 * The firmware takes care of races with the TX handler. */
2634 if (conf->channel_val != phy->channel)
2635 b43legacy_radio_selectchannel(dev, conf->channel_val, 0);
2636
2637 /* Enable/Disable ShortSlot timing. */
2638 if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
2639 != dev->short_slot) {
2640 B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G);
2641 if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
2642 b43legacy_short_slot_timing_enable(dev);
2643 else
2644 b43legacy_short_slot_timing_disable(dev);
2645 }
2646
2647 /* Adjust the desired TX power level. */
2648 if (conf->power_level != 0) {
2649 if (conf->power_level != phy->power_level) {
2650 phy->power_level = conf->power_level;
2651 b43legacy_phy_xmitpower(dev);
2652 }
2653 }
2654
2655 /* Antennas for RX and management frame TX. */
2656 b43legacy_mgmtframe_txantenna(dev, antenna_tx);
2657
2658 /* Update templates for AP mode. */
2659 if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
2660 b43legacy_set_beacon_int(dev, conf->beacon_int);
2661
2662
2663 spin_lock_irqsave(&wl->irq_lock, flags);
2664 b43legacy_interrupt_enable(dev, savedirqs);
2665 mmiowb();
2666 spin_unlock_irqrestore(&wl->irq_lock, flags);
2667out_unlock_mutex:
2668 mutex_unlock(&wl->mutex);
2669
2670 return err;
2671}
2672
2673static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
2674 set_key_cmd cmd,
2675 const u8 *local_addr, const u8 *addr,
2676 struct ieee80211_key_conf *key)
2677{
2678 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2679 struct b43legacy_wldev *dev = wl->current_dev;
2680 unsigned long flags;
2681 int err = -EOPNOTSUPP;
2682
2683 if (!dev)
2684 return -ENODEV;
2685 mutex_lock(&wl->mutex);
2686 spin_lock_irqsave(&wl->irq_lock, flags);
2687
2688 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
2689 err = -ENODEV;
2690 }
2691 spin_unlock_irqrestore(&wl->irq_lock, flags);
2692 mutex_unlock(&wl->mutex);
2693 b43legacydbg(wl, "Using software based encryption for "
2694 "mac: " MAC_FMT "\n", MAC_ARG(addr));
2695 return err;
2696}
2697
2698static void b43legacy_set_multicast_list(struct ieee80211_hw *hw,
2699 unsigned short netflags,
2700 int mc_count)
2701{
2702 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2703 struct b43legacy_wldev *dev = wl->current_dev;
2704 unsigned long flags;
2705
2706 if (!dev)
2707 return;
2708 spin_lock_irqsave(&wl->irq_lock, flags);
2709 if (wl->promisc != !!(netflags & IFF_PROMISC)) {
2710 wl->promisc = !!(netflags & IFF_PROMISC);
2711 if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
2712 b43legacy_adjust_opmode(dev);
2713 }
2714 spin_unlock_irqrestore(&wl->irq_lock, flags);
2715}
2716
2717static int b43legacy_config_interface(struct ieee80211_hw *hw,
2718 int if_id,
2719 struct ieee80211_if_conf *conf)
2720{
2721 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2722 struct b43legacy_wldev *dev = wl->current_dev;
2723 unsigned long flags;
2724
2725 if (!dev)
2726 return -ENODEV;
2727 mutex_lock(&wl->mutex);
2728 spin_lock_irqsave(&wl->irq_lock, flags);
2729 if (conf->type != IEEE80211_IF_TYPE_MNTR) {
2730 B43legacy_WARN_ON(wl->if_id != if_id);
2731 wl->bssid = conf->bssid;
2732 if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
2733 if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
2734 B43legacy_WARN_ON(conf->type !=
2735 IEEE80211_IF_TYPE_AP);
2736 b43legacy_set_ssid(dev, conf->ssid,
2737 conf->ssid_len);
2738 if (conf->beacon)
2739 b43legacy_refresh_templates(dev,
2740 conf->beacon);
2741 }
2742 b43legacy_write_mac_bssid_templates(dev);
2743 }
2744 }
2745 spin_unlock_irqrestore(&wl->irq_lock, flags);
2746 mutex_unlock(&wl->mutex);
2747
2748 return 0;
2749}
2750
2751/* Locking: wl->mutex */
2752static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
2753{
2754 struct b43legacy_wl *wl = dev->wl;
2755 unsigned long flags;
2756
2757 if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
2758 return;
2759 b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
2760
2761 mutex_unlock(&wl->mutex);
2762 /* Must unlock as it would otherwise deadlock. No races here.
2763 * Cancel the possibly running self-rearming periodic work. */
2764 cancel_delayed_work_sync(&dev->periodic_work);
2765 mutex_lock(&wl->mutex);
2766
2767 ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
2768
2769 /* Disable and sync interrupts. */
2770 spin_lock_irqsave(&wl->irq_lock, flags);
2771 dev->irq_savedstate = b43legacy_interrupt_disable(dev,
2772 B43legacy_IRQ_ALL);
2773 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
2774 spin_unlock_irqrestore(&wl->irq_lock, flags);
2775 b43legacy_synchronize_irq(dev);
2776
2777 b43legacy_mac_suspend(dev);
2778 free_irq(dev->dev->irq, dev);
2779 b43legacydbg(wl, "Wireless interface stopped\n");
2780}
2781
2782/* Locking: wl->mutex */
2783static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
2784{
2785 int err;
2786
2787 B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_INITIALIZED);
2788
2789 drain_txstatus_queue(dev);
2790 err = request_irq(dev->dev->irq, b43legacy_interrupt_handler,
2791 IRQF_SHARED, KBUILD_MODNAME, dev);
2792 if (err) {
2793 b43legacyerr(dev->wl, "Cannot request IRQ-%d\n",
2794 dev->dev->irq);
2795 goto out;
2796 }
2797 /* We are ready to run. */
2798 b43legacy_set_status(dev, B43legacy_STAT_STARTED);
2799
2800 /* Start data flow (TX/RX) */
2801 b43legacy_mac_enable(dev);
2802 b43legacy_interrupt_enable(dev, dev->irq_savedstate);
2803 ieee80211_start_queues(dev->wl->hw);
2804
2805 /* Start maintenance work */
2806 b43legacy_periodic_tasks_setup(dev);
2807
2808 b43legacydbg(dev->wl, "Wireless interface started\n");
2809out:
2810 return err;
2811}
2812
2813/* Get PHY and RADIO versioning numbers */
2814static int b43legacy_phy_versioning(struct b43legacy_wldev *dev)
2815{
2816 struct b43legacy_phy *phy = &dev->phy;
2817 u32 tmp;
2818 u8 analog_type;
2819 u8 phy_type;
2820 u8 phy_rev;
2821 u16 radio_manuf;
2822 u16 radio_ver;
2823 u16 radio_rev;
2824 int unsupported = 0;
2825
2826 /* Get PHY versioning */
2827 tmp = b43legacy_read16(dev, B43legacy_MMIO_PHY_VER);
2828 analog_type = (tmp & B43legacy_PHYVER_ANALOG)
2829 >> B43legacy_PHYVER_ANALOG_SHIFT;
2830 phy_type = (tmp & B43legacy_PHYVER_TYPE) >> B43legacy_PHYVER_TYPE_SHIFT;
2831 phy_rev = (tmp & B43legacy_PHYVER_VERSION);
2832 switch (phy_type) {
2833 case B43legacy_PHYTYPE_B:
2834 if (phy_rev != 2 && phy_rev != 4
2835 && phy_rev != 6 && phy_rev != 7)
2836 unsupported = 1;
2837 break;
2838 case B43legacy_PHYTYPE_G:
2839 if (phy_rev > 8)
2840 unsupported = 1;
2841 break;
2842 default:
2843 unsupported = 1;
2844 };
2845 if (unsupported) {
2846 b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY "
2847 "(Analog %u, Type %u, Revision %u)\n",
2848 analog_type, phy_type, phy_rev);
2849 return -EOPNOTSUPP;
2850 }
2851 b43legacydbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
2852 analog_type, phy_type, phy_rev);
2853
2854
2855 /* Get RADIO versioning */
2856 if (dev->dev->bus->chip_id == 0x4317) {
2857 if (dev->dev->bus->chip_rev == 0)
2858 tmp = 0x3205017F;
2859 else if (dev->dev->bus->chip_rev == 1)
2860 tmp = 0x4205017F;
2861 else
2862 tmp = 0x5205017F;
2863 } else {
2864 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
2865 B43legacy_RADIOCTL_ID);
2866 tmp = b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_HIGH);
2867 tmp <<= 16;
2868 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
2869 B43legacy_RADIOCTL_ID);
2870 tmp |= b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
2871 }
2872 radio_manuf = (tmp & 0x00000FFF);
2873 radio_ver = (tmp & 0x0FFFF000) >> 12;
2874 radio_rev = (tmp & 0xF0000000) >> 28;
2875 switch (phy_type) {
2876 case B43legacy_PHYTYPE_B:
2877 if ((radio_ver & 0xFFF0) != 0x2050)
2878 unsupported = 1;
2879 break;
2880 case B43legacy_PHYTYPE_G:
2881 if (radio_ver != 0x2050)
2882 unsupported = 1;
2883 break;
2884 default:
2885 B43legacy_BUG_ON(1);
2886 }
2887 if (unsupported) {
2888 b43legacyerr(dev->wl, "FOUND UNSUPPORTED RADIO "
2889 "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
2890 radio_manuf, radio_ver, radio_rev);
2891 return -EOPNOTSUPP;
2892 }
2893 b43legacydbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X,"
2894 " Revision %u\n", radio_manuf, radio_ver, radio_rev);
2895
2896
2897 phy->radio_manuf = radio_manuf;
2898 phy->radio_ver = radio_ver;
2899 phy->radio_rev = radio_rev;
2900
2901 phy->analog = analog_type;
2902 phy->type = phy_type;
2903 phy->rev = phy_rev;
2904
2905 return 0;
2906}
2907
2908static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
2909 struct b43legacy_phy *phy)
2910{
2911 struct b43legacy_lopair *lo;
2912 int i;
2913
2914 memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
2915 memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
2916
2917 /* Flags */
2918 phy->locked = 0;
2919
2920 phy->savedpctlreg = 0xFFFF;
2921 phy->aci_enable = 0;
2922 phy->aci_wlan_automatic = 0;
2923 phy->aci_hw_rssi = 0;
2924
2925 lo = phy->_lo_pairs;
2926 if (lo)
2927 memset(lo, 0, sizeof(struct b43legacy_lopair) *
2928 B43legacy_LO_COUNT);
2929 phy->max_lb_gain = 0;
2930 phy->trsw_rx_gain = 0;
2931
2932 /* Set default attenuation values. */
2933 phy->bbatt = b43legacy_default_baseband_attenuation(dev);
2934 phy->rfatt = b43legacy_default_radio_attenuation(dev);
2935 phy->txctl1 = b43legacy_default_txctl1(dev);
2936 phy->txpwr_offset = 0;
2937
2938 /* NRSSI */
2939 phy->nrssislope = 0;
2940 for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
2941 phy->nrssi[i] = -1000;
2942 for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
2943 phy->nrssi_lt[i] = i;
2944
2945 phy->lofcal = 0xFFFF;
2946 phy->initval = 0xFFFF;
2947
2948 spin_lock_init(&phy->lock);
2949 phy->interfmode = B43legacy_INTERFMODE_NONE;
2950 phy->channel = 0xFF;
2951}
2952
2953static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
2954{
2955 /* Flags */
2956 dev->reg124_set_0x4 = 0;
2957
2958 /* Stats */
2959 memset(&dev->stats, 0, sizeof(dev->stats));
2960
2961 setup_struct_phy_for_init(dev, &dev->phy);
2962
2963 /* IRQ related flags */
2964 dev->irq_reason = 0;
2965 memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
2966 dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE;
2967
2968 dev->mac_suspended = 1;
2969
2970 /* Noise calculation context */
2971 memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
2972}
2973
2974static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
2975{
2976#ifdef CONFIG_SSB_DRIVER_PCICORE
2977 struct ssb_bus *bus = dev->dev->bus;
2978 u32 tmp;
2979
2980 if (bus->pcicore.dev &&
2981 bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
2982 bus->pcicore.dev->id.revision <= 5) {
2983 /* IMCFGLO timeouts workaround. */
2984 tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
2985 tmp &= ~SSB_IMCFGLO_REQTO;
2986 tmp &= ~SSB_IMCFGLO_SERTO;
2987 switch (bus->bustype) {
2988 case SSB_BUSTYPE_PCI:
2989 case SSB_BUSTYPE_PCMCIA:
2990 tmp |= 0x32;
2991 break;
2992 case SSB_BUSTYPE_SSB:
2993 tmp |= 0x53;
2994 break;
2995 }
2996 ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
2997 }
2998#endif /* CONFIG_SSB_DRIVER_PCICORE */
2999}
3000
3001/* Shutdown a wireless core */
3002/* Locking: wl->mutex */
3003static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
3004{
3005 struct b43legacy_wl *wl = dev->wl;
3006 struct b43legacy_phy *phy = &dev->phy;
3007
3008 B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED);
3009 if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED)
3010 return;
3011 b43legacy_set_status(dev, B43legacy_STAT_UNINIT);
3012
3013 mutex_unlock(&wl->mutex);
3014 /* Must unlock as it would otherwise deadlock. No races here.
3015 * Cancel possibly pending workqueues. */
3016 cancel_work_sync(&dev->restart_work);
3017 mutex_lock(&wl->mutex);
3018
3019 b43legacy_rng_exit(dev->wl);
3020 b43legacy_pio_free(dev);
3021 b43legacy_dma_free(dev);
3022 b43legacy_chip_exit(dev);
3023 b43legacy_radio_turn_off(dev);
3024 b43legacy_switch_analog(dev, 0);
3025 if (phy->dyn_tssi_tbl)
3026 kfree(phy->tssi2dbm);
3027 kfree(phy->lo_control);
3028 phy->lo_control = NULL;
3029 ssb_device_disable(dev->dev, 0);
3030 ssb_bus_may_powerdown(dev->dev->bus);
3031}
3032
3033static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
3034{
3035 struct b43legacy_phy *phy = &dev->phy;
3036 int i;
3037
3038 /* Set default attenuation values. */
3039 phy->bbatt = b43legacy_default_baseband_attenuation(dev);
3040 phy->rfatt = b43legacy_default_radio_attenuation(dev);
3041 phy->txctl1 = b43legacy_default_txctl1(dev);
3042 phy->txctl2 = 0xFFFF;
3043 phy->txpwr_offset = 0;
3044
3045 /* NRSSI */
3046 phy->nrssislope = 0;
3047 for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
3048 phy->nrssi[i] = -1000;
3049 for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
3050 phy->nrssi_lt[i] = i;
3051
3052 phy->lofcal = 0xFFFF;
3053 phy->initval = 0xFFFF;
3054
3055 phy->aci_enable = 0;
3056 phy->aci_wlan_automatic = 0;
3057 phy->aci_hw_rssi = 0;
3058
3059 phy->antenna_diversity = 0xFFFF;
3060 memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
3061 memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
3062
3063 /* Flags */
3064 phy->calibrated = 0;
3065 phy->locked = 0;
3066
3067 if (phy->_lo_pairs)
3068 memset(phy->_lo_pairs, 0,
3069 sizeof(struct b43legacy_lopair) * B43legacy_LO_COUNT);
3070 memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
3071}
3072
3073/* Initialize a wireless core */
3074static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
3075{
3076 struct b43legacy_wl *wl = dev->wl;
3077 struct ssb_bus *bus = dev->dev->bus;
3078 struct b43legacy_phy *phy = &dev->phy;
3079 struct ssb_sprom *sprom = &dev->dev->bus->sprom;
3080 int err;
3081 u32 hf;
3082 u32 tmp;
3083
3084 B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
3085
3086 err = ssb_bus_powerup(bus, 0);
3087 if (err)
3088 goto out;
3089 if (!ssb_device_is_enabled(dev->dev)) {
3090 tmp = phy->gmode ? B43legacy_TMSLOW_GMODE : 0;
3091 b43legacy_wireless_core_reset(dev, tmp);
3092 }
3093
3094 if ((phy->type == B43legacy_PHYTYPE_B) ||
3095 (phy->type == B43legacy_PHYTYPE_G)) {
3096 phy->_lo_pairs = kzalloc(sizeof(struct b43legacy_lopair)
3097 * B43legacy_LO_COUNT,
3098 GFP_KERNEL);
3099 if (!phy->_lo_pairs)
3100 return -ENOMEM;
3101 }
3102 setup_struct_wldev_for_init(dev);
3103
3104 err = b43legacy_phy_init_tssi2dbm_table(dev);
3105 if (err)
3106 goto err_kfree_lo_control;
3107
3108 /* Enable IRQ routing to this device. */
3109 ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
3110
3111 b43legacy_imcfglo_timeouts_workaround(dev);
3112 prepare_phy_data_for_init(dev);
3113 b43legacy_phy_calibrate(dev);
3114 err = b43legacy_chip_init(dev);
3115 if (err)
3116 goto err_kfree_tssitbl;
3117 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
3118 B43legacy_SHM_SH_WLCOREREV,
3119 dev->dev->id.revision);
3120 hf = b43legacy_hf_read(dev);
3121 if (phy->type == B43legacy_PHYTYPE_G) {
3122 hf |= B43legacy_HF_SYMW;
3123 if (phy->rev == 1)
3124 hf |= B43legacy_HF_GDCW;
3125 if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL)
3126 hf |= B43legacy_HF_OFDMPABOOST;
3127 } else if (phy->type == B43legacy_PHYTYPE_B) {
3128 hf |= B43legacy_HF_SYMW;
3129 if (phy->rev >= 2 && phy->radio_ver == 0x2050)
3130 hf &= ~B43legacy_HF_GDCW;
3131 }
3132 b43legacy_hf_write(dev, hf);
3133
3134 /* Short/Long Retry Limit.
3135 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
3136 * the chip-internal counter.
3137 */
3138 tmp = limit_value(modparam_short_retry, 0, 0xF);
3139 b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
3140 0x0006, tmp);
3141 tmp = limit_value(modparam_long_retry, 0, 0xF);
3142 b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
3143 0x0007, tmp);
3144
3145 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
3146 0x0044, 3);
3147 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
3148 0x0046, 2);
3149
3150 /* Disable sending probe responses from firmware.
3151 * Setting the MaxTime to one usec will always trigger
3152 * a timeout, so we never send any probe resp.
3153 * A timeout of zero is infinite. */
3154 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
3155 B43legacy_SHM_SH_PRMAXTIME, 1);
3156
3157 b43legacy_rate_memory_init(dev);
3158
3159 /* Minimum Contention Window */
3160 if (phy->type == B43legacy_PHYTYPE_B)
3161 b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
3162 0x0003, 31);
3163 else
3164 b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
3165 0x0003, 15);
3166 /* Maximum Contention Window */
3167 b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
3168 0x0004, 1023);
3169
3170 do {
3171 if (b43legacy_using_pio(dev))
3172 err = b43legacy_pio_init(dev);
3173 else {
3174 err = b43legacy_dma_init(dev);
3175 if (!err)
3176 b43legacy_qos_init(dev);
3177 }
3178 } while (err == -EAGAIN);
3179 if (err)
3180 goto err_chip_exit;
3181
3182 b43legacy_write16(dev, 0x0612, 0x0050);
3183 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050);
3184 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
3185
3186 ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
3187 wl->bssid = NULL;
3188 b43legacy_upload_card_macaddress(dev, NULL);
3189 b43legacy_security_init(dev);
3190 b43legacy_rng_init(wl);
3191
3192 b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
3193
3194out:
3195 return err;
3196
3197err_chip_exit:
3198 b43legacy_chip_exit(dev);
3199err_kfree_tssitbl:
3200 if (phy->dyn_tssi_tbl)
3201 kfree(phy->tssi2dbm);
3202err_kfree_lo_control:
3203 kfree(phy->lo_control);
3204 phy->lo_control = NULL;
3205 ssb_bus_may_powerdown(bus);
3206 B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
3207 return err;
3208}
3209
3210static int b43legacy_add_interface(struct ieee80211_hw *hw,
3211 struct ieee80211_if_init_conf *conf)
3212{
3213 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
3214 struct b43legacy_wldev *dev;
3215 unsigned long flags;
3216 int err = -EOPNOTSUPP;
3217 int did_init = 0;
3218
3219 mutex_lock(&wl->mutex);
3220 if ((conf->type != IEEE80211_IF_TYPE_MNTR) &&
3221 wl->operating)
3222 goto out_mutex_unlock;
3223
3224 b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
3225
3226 dev = wl->current_dev;
3227 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
3228 err = b43legacy_wireless_core_init(dev);
3229 if (err)
3230 goto out_mutex_unlock;
3231 did_init = 1;
3232 }
3233 if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
3234 err = b43legacy_wireless_core_start(dev);
3235 if (err) {
3236 if (did_init)
3237 b43legacy_wireless_core_exit(dev);
3238 goto out_mutex_unlock;
3239 }
3240 }
3241
3242 spin_lock_irqsave(&wl->irq_lock, flags);
3243 switch (conf->type) {
3244 case IEEE80211_IF_TYPE_MNTR:
3245 wl->monitor++;
3246 break;
3247 default:
3248 wl->operating = 1;
3249 wl->if_id = conf->if_id;
3250 wl->if_type = conf->type;
3251 b43legacy_upload_card_macaddress(dev, conf->mac_addr);
3252 }
3253 b43legacy_adjust_opmode(dev);
3254 spin_unlock_irqrestore(&wl->irq_lock, flags);
3255
3256 err = 0;
3257out_mutex_unlock:
3258 mutex_unlock(&wl->mutex);
3259
3260 return err;
3261}
3262
3263static void b43legacy_remove_interface(struct ieee80211_hw *hw,
3264 struct ieee80211_if_init_conf *conf)
3265{
3266 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
3267 struct b43legacy_wldev *dev;
3268 unsigned long flags;
3269
3270 b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
3271
3272 mutex_lock(&wl->mutex);
3273 if (conf->type == IEEE80211_IF_TYPE_MNTR) {
3274 wl->monitor--;
3275 B43legacy_WARN_ON(wl->monitor < 0);
3276 } else {
3277 B43legacy_WARN_ON(!wl->operating);
3278 wl->operating = 0;
3279 }
3280
3281 dev = wl->current_dev;
3282 if (!wl->operating && wl->monitor == 0) {
3283 /* No interface left. */
3284 if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
3285 b43legacy_wireless_core_stop(dev);
3286 b43legacy_wireless_core_exit(dev);
3287 } else {
3288 /* Just monitor interfaces left. */
3289 spin_lock_irqsave(&wl->irq_lock, flags);
3290 b43legacy_adjust_opmode(dev);
3291 if (!wl->operating)
3292 b43legacy_upload_card_macaddress(dev, NULL);
3293 spin_unlock_irqrestore(&wl->irq_lock, flags);
3294 }
3295 mutex_unlock(&wl->mutex);
3296}
3297
3298
3299static const struct ieee80211_ops b43legacy_hw_ops = {
3300 .tx = b43legacy_tx,
3301 .conf_tx = b43legacy_conf_tx,
3302 .add_interface = b43legacy_add_interface,
3303 .remove_interface = b43legacy_remove_interface,
3304 .config = b43legacy_dev_config,
3305 .config_interface = b43legacy_config_interface,
3306 .set_key = b43legacy_dev_set_key,
3307 .set_multicast_list = b43legacy_set_multicast_list,
3308 .get_stats = b43legacy_get_stats,
3309 .get_tx_stats = b43legacy_get_tx_stats,
3310};
3311
3312/* Hard-reset the chip. Do not call this directly.
3313 * Use b43legacy_controller_restart()
3314 */
3315static void b43legacy_chip_reset(struct work_struct *work)
3316{
3317 struct b43legacy_wldev *dev =
3318 container_of(work, struct b43legacy_wldev, restart_work);
3319 struct b43legacy_wl *wl = dev->wl;
3320 int err = 0;
3321 int prev_status;
3322
3323 mutex_lock(&wl->mutex);
3324
3325 prev_status = b43legacy_status(dev);
3326 /* Bring the device down... */
3327 if (prev_status >= B43legacy_STAT_STARTED)
3328 b43legacy_wireless_core_stop(dev);
3329 if (prev_status >= B43legacy_STAT_INITIALIZED)
3330 b43legacy_wireless_core_exit(dev);
3331
3332 /* ...and up again. */
3333 if (prev_status >= B43legacy_STAT_INITIALIZED) {
3334 err = b43legacy_wireless_core_init(dev);
3335 if (err)
3336 goto out;
3337 }
3338 if (prev_status >= B43legacy_STAT_STARTED) {
3339 err = b43legacy_wireless_core_start(dev);
3340 if (err) {
3341 b43legacy_wireless_core_exit(dev);
3342 goto out;
3343 }
3344 }
3345out:
3346 mutex_unlock(&wl->mutex);
3347 if (err)
3348 b43legacyerr(wl, "Controller restart FAILED\n");
3349 else
3350 b43legacyinfo(wl, "Controller restarted\n");
3351}
3352
3353static int b43legacy_setup_modes(struct b43legacy_wldev *dev,
3354 int have_bphy,
3355 int have_gphy)
3356{
3357 struct ieee80211_hw *hw = dev->wl->hw;
3358 struct ieee80211_hw_mode *mode;
3359 struct b43legacy_phy *phy = &dev->phy;
3360 int cnt = 0;
3361 int err;
3362
3363 phy->possible_phymodes = 0;
3364 for (; 1; cnt++) {
3365 if (have_bphy) {
3366 B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
3367 mode = &phy->hwmodes[cnt];
3368
3369 mode->mode = MODE_IEEE80211B;
3370 mode->num_channels = b43legacy_bg_chantable_size;
3371 mode->channels = b43legacy_bg_chantable;
3372 mode->num_rates = b43legacy_b_ratetable_size;
3373 mode->rates = b43legacy_b_ratetable;
3374 err = ieee80211_register_hwmode(hw, mode);
3375 if (err)
3376 return err;
3377
3378 phy->possible_phymodes |= B43legacy_PHYMODE_B;
3379 have_bphy = 0;
3380 continue;
3381 }
3382 if (have_gphy) {
3383 B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
3384 mode = &phy->hwmodes[cnt];
3385
3386 mode->mode = MODE_IEEE80211G;
3387 mode->num_channels = b43legacy_bg_chantable_size;
3388 mode->channels = b43legacy_bg_chantable;
3389 mode->num_rates = b43legacy_g_ratetable_size;
3390 mode->rates = b43legacy_g_ratetable;
3391 err = ieee80211_register_hwmode(hw, mode);
3392 if (err)
3393 return err;
3394
3395 phy->possible_phymodes |= B43legacy_PHYMODE_G;
3396 have_gphy = 0;
3397 continue;
3398 }
3399 break;
3400 }
3401
3402 return 0;
3403}
3404
3405static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev)
3406{
3407 /* We release firmware that late to not be required to re-request
3408 * is all the time when we reinit the core. */
3409 b43legacy_release_firmware(dev);
3410}
3411
3412static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
3413{
3414 struct b43legacy_wl *wl = dev->wl;
3415 struct ssb_bus *bus = dev->dev->bus;
3416 struct pci_dev *pdev = bus->host_pci;
3417 int err;
3418 int have_bphy = 0;
3419 int have_gphy = 0;
3420 u32 tmp;
3421
3422 /* Do NOT do any device initialization here.
3423 * Do it in wireless_core_init() instead.
3424 * This function is for gathering basic information about the HW, only.
3425 * Also some structs may be set up here. But most likely you want to
3426 * have that in core_init(), too.
3427 */
3428
3429 err = ssb_bus_powerup(bus, 0);
3430 if (err) {
3431 b43legacyerr(wl, "Bus powerup failed\n");
3432 goto out;
3433 }
3434 /* Get the PHY type. */
3435 if (dev->dev->id.revision >= 5) {
3436 u32 tmshigh;
3437
3438 tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
3439 have_gphy = !!(tmshigh & B43legacy_TMSHIGH_GPHY);
3440 if (!have_gphy)
3441 have_bphy = 1;
3442 } else if (dev->dev->id.revision == 4)
3443 have_gphy = 1;
3444 else
3445 have_bphy = 1;
3446
3447 /* Initialize LEDs structs. */
3448 err = b43legacy_leds_init(dev);
3449 if (err)
3450 goto err_powerdown;
3451
3452 dev->phy.gmode = (have_gphy || have_bphy);
3453 tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
3454 b43legacy_wireless_core_reset(dev, tmp);
3455
3456 err = b43legacy_phy_versioning(dev);
3457 if (err)
3458 goto err_leds_exit;
3459 /* Check if this device supports multiband. */
3460 if (!pdev ||
3461 (pdev->device != 0x4312 &&
3462 pdev->device != 0x4319 &&
3463 pdev->device != 0x4324)) {
3464 /* No multiband support. */
3465 have_bphy = 0;
3466 have_gphy = 0;
3467 switch (dev->phy.type) {
3468 case B43legacy_PHYTYPE_B:
3469 have_bphy = 1;
3470 break;
3471 case B43legacy_PHYTYPE_G:
3472 have_gphy = 1;
3473 break;
3474 default:
3475 B43legacy_BUG_ON(1);
3476 }
3477 }
3478 dev->phy.gmode = (have_gphy || have_bphy);
3479 tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
3480 b43legacy_wireless_core_reset(dev, tmp);
3481
3482 err = b43legacy_validate_chipaccess(dev);
3483 if (err)
3484 goto err_leds_exit;
3485 err = b43legacy_setup_modes(dev, have_bphy, have_gphy);
3486 if (err)
3487 goto err_leds_exit;
3488
3489 /* Now set some default "current_dev" */
3490 if (!wl->current_dev)
3491 wl->current_dev = dev;
3492 INIT_WORK(&dev->restart_work, b43legacy_chip_reset);
3493
3494 b43legacy_radio_turn_off(dev);
3495 b43legacy_switch_analog(dev, 0);
3496 ssb_device_disable(dev->dev, 0);
3497 ssb_bus_may_powerdown(bus);
3498
3499out:
3500 return err;
3501
3502err_leds_exit:
3503 b43legacy_leds_exit(dev);
3504err_powerdown:
3505 ssb_bus_may_powerdown(bus);
3506 return err;
3507}
3508
3509static void b43legacy_one_core_detach(struct ssb_device *dev)
3510{
3511 struct b43legacy_wldev *wldev;
3512 struct b43legacy_wl *wl;
3513
3514 wldev = ssb_get_drvdata(dev);
3515 wl = wldev->wl;
3516 cancel_work_sync(&wldev->restart_work);
3517 b43legacy_debugfs_remove_device(wldev);
3518 b43legacy_wireless_core_detach(wldev);
3519 list_del(&wldev->list);
3520 wl->nr_devs--;
3521 ssb_set_drvdata(dev, NULL);
3522 kfree(wldev);
3523}
3524
3525static int b43legacy_one_core_attach(struct ssb_device *dev,
3526 struct b43legacy_wl *wl)
3527{
3528 struct b43legacy_wldev *wldev;
3529 struct pci_dev *pdev;
3530 int err = -ENOMEM;
3531
3532 if (!list_empty(&wl->devlist)) {
3533 /* We are not the first core on this chip. */
3534 pdev = dev->bus->host_pci;
3535 /* Only special chips support more than one wireless
3536 * core, although some of the other chips have more than
3537 * one wireless core as well. Check for this and
3538 * bail out early.
3539 */
3540 if (!pdev ||
3541 ((pdev->device != 0x4321) &&
3542 (pdev->device != 0x4313) &&
3543 (pdev->device != 0x431A))) {
3544 b43legacydbg(wl, "Ignoring unconnected 802.11 core\n");
3545 return -ENODEV;
3546 }
3547 }
3548
3549 wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
3550 if (!wldev)
3551 goto out;
3552
3553 wldev->dev = dev;
3554 wldev->wl = wl;
3555 b43legacy_set_status(wldev, B43legacy_STAT_UNINIT);
3556 wldev->bad_frames_preempt = modparam_bad_frames_preempt;
3557 tasklet_init(&wldev->isr_tasklet,
3558 (void (*)(unsigned long))b43legacy_interrupt_tasklet,
3559 (unsigned long)wldev);
3560 if (modparam_pio)
3561 wldev->__using_pio = 1;
3562 INIT_LIST_HEAD(&wldev->list);
3563
3564 err = b43legacy_wireless_core_attach(wldev);
3565 if (err)
3566 goto err_kfree_wldev;
3567
3568 list_add(&wldev->list, &wl->devlist);
3569 wl->nr_devs++;
3570 ssb_set_drvdata(dev, wldev);
3571 b43legacy_debugfs_add_device(wldev);
3572out:
3573 return err;
3574
3575err_kfree_wldev:
3576 kfree(wldev);
3577 return err;
3578}
3579
3580static void b43legacy_sprom_fixup(struct ssb_bus *bus)
3581{
3582 /* boardflags workarounds */
3583 if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
3584 bus->boardinfo.type == 0x4E &&
3585 bus->boardinfo.rev > 0x40)
3586 bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL;
3587
3588 /* Convert Antennagain values to Q5.2 */
3589 if (bus->sprom.r1.antenna_gain_bg == 0xFF)
3590 bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */
3591 bus->sprom.r1.antenna_gain_bg <<= 2;
3592}
3593
3594static void b43legacy_wireless_exit(struct ssb_device *dev,
3595 struct b43legacy_wl *wl)
3596{
3597 struct ieee80211_hw *hw = wl->hw;
3598
3599 ssb_set_devtypedata(dev, NULL);
3600 ieee80211_free_hw(hw);
3601}
3602
3603static int b43legacy_wireless_init(struct ssb_device *dev)
3604{
3605 struct ssb_sprom *sprom = &dev->bus->sprom;
3606 struct ieee80211_hw *hw;
3607 struct b43legacy_wl *wl;
3608 int err = -ENOMEM;
3609
3610 b43legacy_sprom_fixup(dev->bus);
3611
3612 hw = ieee80211_alloc_hw(sizeof(*wl), &b43legacy_hw_ops);
3613 if (!hw) {
3614 b43legacyerr(NULL, "Could not allocate ieee80211 device\n");
3615 goto out;
3616 }
3617
3618 /* fill hw info */
3619 hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
3620 IEEE80211_HW_RX_INCLUDES_FCS;
3621 hw->max_signal = 100;
3622 hw->max_rssi = -110;
3623 hw->max_noise = -110;
3624 hw->queues = 1; /* FIXME: hardware has more queues */
3625 SET_IEEE80211_DEV(hw, dev->dev);
3626 if (is_valid_ether_addr(sprom->r1.et1mac))
3627 SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
3628 else
3629 SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
3630
3631 /* Get and initialize struct b43legacy_wl */
3632 wl = hw_to_b43legacy_wl(hw);
3633 memset(wl, 0, sizeof(*wl));
3634 wl->hw = hw;
3635 spin_lock_init(&wl->irq_lock);
3636 spin_lock_init(&wl->leds_lock);
3637 mutex_init(&wl->mutex);
3638 INIT_LIST_HEAD(&wl->devlist);
3639
3640 ssb_set_devtypedata(dev, wl);
3641 b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
3642 err = 0;
3643out:
3644 return err;
3645}
3646
3647static int b43legacy_probe(struct ssb_device *dev,
3648 const struct ssb_device_id *id)
3649{
3650 struct b43legacy_wl *wl;
3651 int err;
3652 int first = 0;
3653
3654 wl = ssb_get_devtypedata(dev);
3655 if (!wl) {
3656 /* Probing the first core - setup common struct b43legacy_wl */
3657 first = 1;
3658 err = b43legacy_wireless_init(dev);
3659 if (err)
3660 goto out;
3661 wl = ssb_get_devtypedata(dev);
3662 B43legacy_WARN_ON(!wl);
3663 }
3664 err = b43legacy_one_core_attach(dev, wl);
3665 if (err)
3666 goto err_wireless_exit;
3667
3668 if (first) {
3669 err = ieee80211_register_hw(wl->hw);
3670 if (err)
3671 goto err_one_core_detach;
3672 }
3673
3674out:
3675 return err;
3676
3677err_one_core_detach:
3678 b43legacy_one_core_detach(dev);
3679err_wireless_exit:
3680 if (first)
3681 b43legacy_wireless_exit(dev, wl);
3682 return err;
3683}
3684
3685static void b43legacy_remove(struct ssb_device *dev)
3686{
3687 struct b43legacy_wl *wl = ssb_get_devtypedata(dev);
3688 struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
3689
3690 B43legacy_WARN_ON(!wl);
3691 if (wl->current_dev == wldev)
3692 ieee80211_unregister_hw(wl->hw);
3693
3694 b43legacy_one_core_detach(dev);
3695
3696 if (list_empty(&wl->devlist))
3697 /* Last core on the chip unregistered.
3698 * We can destroy common struct b43legacy_wl.
3699 */
3700 b43legacy_wireless_exit(dev, wl);
3701}
3702
3703/* Perform a hardware reset. This can be called from any context. */
3704void b43legacy_controller_restart(struct b43legacy_wldev *dev,
3705 const char *reason)
3706{
3707 /* Must avoid requeueing, if we are in shutdown. */
3708 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
3709 return;
3710 b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason);
3711 queue_work(dev->wl->hw->workqueue, &dev->restart_work);
3712}
3713
3714#ifdef CONFIG_PM
3715
3716static int b43legacy_suspend(struct ssb_device *dev, pm_message_t state)
3717{
3718 struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
3719 struct b43legacy_wl *wl = wldev->wl;
3720
3721 b43legacydbg(wl, "Suspending...\n");
3722
3723 mutex_lock(&wl->mutex);
3724 wldev->suspend_init_status = b43legacy_status(wldev);
3725 if (wldev->suspend_init_status >= B43legacy_STAT_STARTED)
3726 b43legacy_wireless_core_stop(wldev);
3727 if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED)
3728 b43legacy_wireless_core_exit(wldev);
3729 mutex_unlock(&wl->mutex);
3730
3731 b43legacydbg(wl, "Device suspended.\n");
3732
3733 return 0;
3734}
3735
3736static int b43legacy_resume(struct ssb_device *dev)
3737{
3738 struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
3739 struct b43legacy_wl *wl = wldev->wl;
3740 int err = 0;
3741
3742 b43legacydbg(wl, "Resuming...\n");
3743
3744 mutex_lock(&wl->mutex);
3745 if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) {
3746 err = b43legacy_wireless_core_init(wldev);
3747 if (err) {
3748 b43legacyerr(wl, "Resume failed at core init\n");
3749 goto out;
3750 }
3751 }
3752 if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) {
3753 err = b43legacy_wireless_core_start(wldev);
3754 if (err) {
3755 b43legacy_wireless_core_exit(wldev);
3756 b43legacyerr(wl, "Resume failed at core start\n");
3757 goto out;
3758 }
3759 }
3760 mutex_unlock(&wl->mutex);
3761
3762 b43legacydbg(wl, "Device resumed.\n");
3763out:
3764 return err;
3765}
3766
3767#else /* CONFIG_PM */
3768# define b43legacy_suspend NULL
3769# define b43legacy_resume NULL
3770#endif /* CONFIG_PM */
3771
3772static struct ssb_driver b43legacy_ssb_driver = {
3773 .name = KBUILD_MODNAME,
3774 .id_table = b43legacy_ssb_tbl,
3775 .probe = b43legacy_probe,
3776 .remove = b43legacy_remove,
3777 .suspend = b43legacy_suspend,
3778 .resume = b43legacy_resume,
3779};
3780
3781static int __init b43legacy_init(void)
3782{
3783 int err;
3784
3785 b43legacy_debugfs_init();
3786
3787 err = ssb_driver_register(&b43legacy_ssb_driver);
3788 if (err)
3789 goto err_dfs_exit;
3790
3791 return err;
3792
3793err_dfs_exit:
3794 b43legacy_debugfs_exit();
3795 return err;
3796}
3797
3798static void __exit b43legacy_exit(void)
3799{
3800 ssb_driver_unregister(&b43legacy_ssb_driver);
3801 b43legacy_debugfs_exit();
3802}
3803
3804module_init(b43legacy_init)
3805module_exit(b43legacy_exit)
diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h
new file mode 100644
index 00000000000..673935e67e6
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.h
@@ -0,0 +1,147 @@
1/*
2
3 Broadcom B43legacy wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
7 Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
8 Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
9 Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10 Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
11
12 Some parts of the code in this file are derived from the ipw2200
13 driver Copyright(c) 2003 - 2004 Intel Corporation.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
28 Boston, MA 02110-1301, USA.
29
30*/
31
32#ifndef B43legacy_MAIN_H_
33#define B43legacy_MAIN_H_
34
35#include "b43legacy.h"
36
37
38#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
39#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
40/* Magic helper macro to pad structures. Ignore those above. It's magic. */
41#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__ , (nr_bytes))
42
43
44/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
45static inline
46u8 b43legacy_freq_to_channel_bg(int freq)
47{
48 u8 channel;
49
50 if (freq == 2484)
51 channel = 14;
52 else
53 channel = (freq - 2407) / 5;
54
55 return channel;
56}
57static inline
58u8 b43legacy_freq_to_channel(struct b43legacy_wldev *dev,
59 int freq)
60{
61 return b43legacy_freq_to_channel_bg(freq);
62}
63
64/* Lightweight function to convert a channel number to a frequency (in Mhz). */
65static inline
66int b43legacy_channel_to_freq_bg(u8 channel)
67{
68 int freq;
69
70 if (channel == 14)
71 freq = 2484;
72 else
73 freq = 2407 + (5 * channel);
74
75 return freq;
76}
77
78static inline
79int b43legacy_channel_to_freq(struct b43legacy_wldev *dev,
80 u8 channel)
81{
82 return b43legacy_channel_to_freq_bg(channel);
83}
84
85static inline
86int b43legacy_is_cck_rate(int rate)
87{
88 return (rate == B43legacy_CCK_RATE_1MB ||
89 rate == B43legacy_CCK_RATE_2MB ||
90 rate == B43legacy_CCK_RATE_5MB ||
91 rate == B43legacy_CCK_RATE_11MB);
92}
93
94static inline
95int b43legacy_is_ofdm_rate(int rate)
96{
97 return !b43legacy_is_cck_rate(rate);
98}
99
100static inline
101int b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
102{
103 /* function to return state of hardware enable of radio
104 * returns 0 if radio disabled, 1 if radio enabled
105 */
106 struct b43legacy_phy *phy = &dev->phy;
107
108 if (phy->rev >= 3)
109 return ((b43legacy_read32(dev,
110 B43legacy_MMIO_RADIO_HWENABLED_HI)
111 & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)
112 == 0) ? 1 : 0;
113 else
114 return ((b43legacy_read16(dev,
115 B43legacy_MMIO_RADIO_HWENABLED_LO)
116 & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
117 == 0) ? 0 : 1;
118}
119
120void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf);
121void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf);
122
123u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
124 u16 routing, u16 offset);
125u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
126 u16 routing, u16 offset);
127void b43legacy_shm_write32(struct b43legacy_wldev *dev,
128 u16 routing, u16 offset,
129 u32 value);
130void b43legacy_shm_write16(struct b43legacy_wldev *dev,
131 u16 routing, u16 offset,
132 u16 value);
133
134u32 b43legacy_hf_read(struct b43legacy_wldev *dev);
135void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value);
136
137void b43legacy_dummy_transmission(struct b43legacy_wldev *dev);
138
139void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags);
140
141void b43legacy_mac_suspend(struct b43legacy_wldev *dev);
142void b43legacy_mac_enable(struct b43legacy_wldev *dev);
143
144void b43legacy_controller_restart(struct b43legacy_wldev *dev,
145 const char *reason);
146
147#endif /* B43legacy_MAIN_H_ */
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
new file mode 100644
index 00000000000..f9edbd5f300
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -0,0 +1,2265 @@
1/*
2
3 Broadcom B43legacy 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 Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
11
12 Some parts of the code in this file are derived from the ipw2200
13 driver Copyright(c) 2003 - 2004 Intel Corporation.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
28 Boston, MA 02110-1301, USA.
29
30*/
31
32#include <linux/delay.h>
33#include <linux/pci.h>
34#include <linux/types.h>
35
36#include "b43legacy.h"
37#include "phy.h"
38#include "main.h"
39#include "radio.h"
40#include "ilt.h"
41
42
43static const s8 b43legacy_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 b43legacy_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 b43legacy_phy_initg(struct b43legacy_wldev *dev);
82
83
84static inline
85void b43legacy_voluntary_preempt(void)
86{
87 B43legacy_BUG_ON(!(!in_atomic() && !in_irq() &&
88 !in_interrupt() && !irqs_disabled()));
89#ifndef CONFIG_PREEMPT
90 cond_resched();
91#endif /* CONFIG_PREEMPT */
92}
93
94void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev)
95{
96 struct b43legacy_phy *phy = &dev->phy;
97
98 B43legacy_WARN_ON(!irqs_disabled());
99 if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) {
100 phy->locked = 0;
101 return;
102 }
103 if (dev->dev->id.revision < 3) {
104 b43legacy_mac_suspend(dev);
105 spin_lock(&phy->lock);
106 } else {
107 if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
108 b43legacy_power_saving_ctl_bits(dev, -1, 1);
109 }
110 phy->locked = 1;
111}
112
113void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev)
114{
115 struct b43legacy_phy *phy = &dev->phy;
116
117 B43legacy_WARN_ON(!irqs_disabled());
118 if (dev->dev->id.revision < 3) {
119 if (phy->locked) {
120 spin_unlock(&phy->lock);
121 b43legacy_mac_enable(dev);
122 }
123 } else {
124 if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
125 b43legacy_power_saving_ctl_bits(dev, -1, -1);
126 }
127 phy->locked = 0;
128}
129
130u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
131{
132 b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
133 return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA);
134}
135
136void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
137{
138 b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
139 mmiowb();
140 b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val);
141}
142
143void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
144{
145 struct b43legacy_phy *phy = &dev->phy;
146
147 b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */
148 if (phy->calibrated)
149 return;
150 if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
151 b43legacy_wireless_core_reset(dev, 0);
152 b43legacy_phy_initg(dev);
153 b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE);
154 }
155 phy->calibrated = 1;
156}
157
158/* intialize B PHY power control
159 * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
160 */
161static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
162{
163 struct b43legacy_phy *phy = &dev->phy;
164 u16 saved_batt = 0;
165 u16 saved_ratt = 0;
166 u16 saved_txctl1 = 0;
167 int must_reset_txpower = 0;
168
169 B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
170 phy->type == B43legacy_PHYTYPE_G));
171 if (is_bcm_board_vendor(dev) &&
172 (dev->dev->bus->boardinfo.type == 0x0416))
173 return;
174
175 b43legacy_phy_write(dev, 0x0028, 0x8018);
176 b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF);
177
178 if (phy->type == B43legacy_PHYTYPE_G) {
179 if (!phy->gmode)
180 return;
181 b43legacy_phy_write(dev, 0x047A, 0xC111);
182 }
183 if (phy->savedpctlreg != 0xFFFF)
184 return;
185#ifdef CONFIG_B43LEGACY_DEBUG
186 if (phy->manual_txpower_control)
187 return;
188#endif
189
190 if (phy->type == B43legacy_PHYTYPE_B &&
191 phy->rev >= 2 &&
192 phy->radio_ver == 0x2050)
193 b43legacy_radio_write16(dev, 0x0076,
194 b43legacy_radio_read16(dev, 0x0076)
195 | 0x0084);
196 else {
197 saved_batt = phy->bbatt;
198 saved_ratt = phy->rfatt;
199 saved_txctl1 = phy->txctl1;
200 if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8)
201 && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
202 b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
203 else
204 b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0);
205 must_reset_txpower = 1;
206 }
207 b43legacy_dummy_transmission(dev);
208
209 phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL);
210
211 if (must_reset_txpower)
212 b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt,
213 saved_txctl1);
214 else
215 b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev,
216 0x0076) & 0xFF7B);
217 b43legacy_radio_clear_tssi(dev);
218}
219
220static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev)
221{
222 struct b43legacy_phy *phy = &dev->phy;
223 u16 offset = 0x0000;
224
225 if (phy->rev == 1)
226 offset = 0x4C00;
227
228 b43legacy_ilt_write(dev, offset, 0x00FE);
229 b43legacy_ilt_write(dev, offset + 1, 0x000D);
230 b43legacy_ilt_write(dev, offset + 2, 0x0013);
231 b43legacy_ilt_write(dev, offset + 3, 0x0019);
232
233 if (phy->rev == 1) {
234 b43legacy_ilt_write(dev, 0x1800, 0x2710);
235 b43legacy_ilt_write(dev, 0x1801, 0x9B83);
236 b43legacy_ilt_write(dev, 0x1802, 0x9B83);
237 b43legacy_ilt_write(dev, 0x1803, 0x0F8D);
238 b43legacy_phy_write(dev, 0x0455, 0x0004);
239 }
240
241 b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5)
242 & 0x00FF) | 0x5700);
243 b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
244 & 0xFF80) | 0x000F);
245 b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
246 & 0xC07F) | 0x2B80);
247 b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C)
248 & 0xF0FF) | 0x0300);
249
250 b43legacy_radio_write16(dev, 0x007A,
251 b43legacy_radio_read16(dev, 0x007A)
252 | 0x0008);
253
254 b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
255 & 0xFFF0) | 0x0008);
256 b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1)
257 & 0xF0FF) | 0x0600);
258 b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2)
259 & 0xF0FF) | 0x0700);
260 b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
261 & 0xF0FF) | 0x0100);
262
263 if (phy->rev == 1)
264 b43legacy_phy_write(dev, 0x04A2,
265 (b43legacy_phy_read(dev, 0x04A2)
266 & 0xFFF0) | 0x0007);
267
268 b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
269 & 0xFF00) | 0x001C);
270 b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
271 & 0xC0FF) | 0x0200);
272 b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
273 & 0xFF00) | 0x001C);
274 b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
275 & 0xFF00) | 0x0020);
276 b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
277 & 0xC0FF) | 0x0200);
278 b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482)
279 & 0xFF00) | 0x002E);
280 b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
281 & 0x00FF) | 0x1A00);
282 b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
283 & 0xFF00) | 0x0028);
284 b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
285 & 0x00FF) | 0x2C00);
286
287 if (phy->rev == 1) {
288 b43legacy_phy_write(dev, 0x0430, 0x092B);
289 b43legacy_phy_write(dev, 0x041B,
290 (b43legacy_phy_read(dev, 0x041B)
291 & 0xFFE1) | 0x0002);
292 } else {
293 b43legacy_phy_write(dev, 0x041B,
294 b43legacy_phy_read(dev, 0x041B) & 0xFFE1);
295 b43legacy_phy_write(dev, 0x041F, 0x287A);
296 b43legacy_phy_write(dev, 0x0420,
297 (b43legacy_phy_read(dev, 0x0420)
298 & 0xFFF0) | 0x0004);
299 }
300
301 if (phy->rev > 2) {
302 b43legacy_phy_write(dev, 0x0422, 0x287A);
303 b43legacy_phy_write(dev, 0x0420,
304 (b43legacy_phy_read(dev, 0x0420)
305 & 0x0FFF) | 0x3000);
306 }
307
308 b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8)
309 & 0x8080) | 0x7874);
310 b43legacy_phy_write(dev, 0x048E, 0x1C00);
311
312 if (phy->rev == 1) {
313 b43legacy_phy_write(dev, 0x04AB,
314 (b43legacy_phy_read(dev, 0x04AB)
315 & 0xF0FF) | 0x0600);
316 b43legacy_phy_write(dev, 0x048B, 0x005E);
317 b43legacy_phy_write(dev, 0x048C,
318 (b43legacy_phy_read(dev, 0x048C) & 0xFF00)
319 | 0x001E);
320 b43legacy_phy_write(dev, 0x048D, 0x0002);
321 }
322
323 b43legacy_ilt_write(dev, offset + 0x0800, 0);
324 b43legacy_ilt_write(dev, offset + 0x0801, 7);
325 b43legacy_ilt_write(dev, offset + 0x0802, 16);
326 b43legacy_ilt_write(dev, offset + 0x0803, 28);
327
328 if (phy->rev >= 6) {
329 b43legacy_phy_write(dev, 0x0426,
330 (b43legacy_phy_read(dev, 0x0426) & 0xFFFC));
331 b43legacy_phy_write(dev, 0x0426,
332 (b43legacy_phy_read(dev, 0x0426) & 0xEFFF));
333 }
334}
335
336static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
337{
338 struct b43legacy_phy *phy = &dev->phy;
339 u16 i;
340
341 B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G);
342 if (phy->rev == 1) {
343 b43legacy_phy_write(dev, 0x0406, 0x4F19);
344 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
345 (b43legacy_phy_read(dev,
346 B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340);
347 b43legacy_phy_write(dev, 0x042C, 0x005A);
348 b43legacy_phy_write(dev, 0x0427, 0x001A);
349
350 for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++)
351 b43legacy_ilt_write(dev, 0x5800 + i,
352 b43legacy_ilt_finefreqg[i]);
353 for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++)
354 b43legacy_ilt_write(dev, 0x1800 + i,
355 b43legacy_ilt_noiseg1[i]);
356 for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++)
357 b43legacy_ilt_write32(dev, 0x2000 + i,
358 b43legacy_ilt_rotor[i]);
359 } else {
360 /* nrssi values are signed 6-bit values. Why 0x7654 here? */
361 b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654);
362
363 if (phy->rev == 2) {
364 b43legacy_phy_write(dev, 0x04C0, 0x1861);
365 b43legacy_phy_write(dev, 0x04C1, 0x0271);
366 } else if (phy->rev > 2) {
367 b43legacy_phy_write(dev, 0x04C0, 0x0098);
368 b43legacy_phy_write(dev, 0x04C1, 0x0070);
369 b43legacy_phy_write(dev, 0x04C9, 0x0080);
370 }
371 b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev,
372 0x042B) | 0x800);
373
374 for (i = 0; i < 64; i++)
375 b43legacy_ilt_write(dev, 0x4000 + i, i);
376 for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++)
377 b43legacy_ilt_write(dev, 0x1800 + i,
378 b43legacy_ilt_noiseg2[i]);
379 }
380
381 if (phy->rev <= 2)
382 for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
383 b43legacy_ilt_write(dev, 0x1400 + i,
384 b43legacy_ilt_noisescaleg1[i]);
385 else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200))
386 for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
387 b43legacy_ilt_write(dev, 0x1400 + i,
388 b43legacy_ilt_noisescaleg3[i]);
389 else
390 for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
391 b43legacy_ilt_write(dev, 0x1400 + i,
392 b43legacy_ilt_noisescaleg2[i]);
393
394 if (phy->rev == 2)
395 for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
396 b43legacy_ilt_write(dev, 0x5000 + i,
397 b43legacy_ilt_sigmasqr1[i]);
398 else if ((phy->rev > 2) && (phy->rev <= 8))
399 for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
400 b43legacy_ilt_write(dev, 0x5000 + i,
401 b43legacy_ilt_sigmasqr2[i]);
402
403 if (phy->rev == 1) {
404 for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++)
405 b43legacy_ilt_write32(dev, 0x2400 + i,
406 b43legacy_ilt_retard[i]);
407 for (i = 4; i < 20; i++)
408 b43legacy_ilt_write(dev, 0x5400 + i, 0x0020);
409 b43legacy_phy_agcsetup(dev);
410
411 if (is_bcm_board_vendor(dev) &&
412 (dev->dev->bus->boardinfo.type == 0x0416) &&
413 (dev->dev->bus->boardinfo.rev == 0x0017))
414 return;
415
416 b43legacy_ilt_write(dev, 0x5001, 0x0002);
417 b43legacy_ilt_write(dev, 0x5002, 0x0001);
418 } else {
419 for (i = 0; i <= 0x20; i++)
420 b43legacy_ilt_write(dev, 0x1000 + i, 0x0820);
421 b43legacy_phy_agcsetup(dev);
422 b43legacy_phy_read(dev, 0x0400); /* dummy read */
423 b43legacy_phy_write(dev, 0x0403, 0x1000);
424 b43legacy_ilt_write(dev, 0x3C02, 0x000F);
425 b43legacy_ilt_write(dev, 0x3C03, 0x0014);
426
427 if (is_bcm_board_vendor(dev) &&
428 (dev->dev->bus->boardinfo.type == 0x0416) &&
429 (dev->dev->bus->boardinfo.rev == 0x0017))
430 return;
431
432 b43legacy_ilt_write(dev, 0x0401, 0x0002);
433 b43legacy_ilt_write(dev, 0x0402, 0x0001);
434 }
435}
436
437/* Initialize the APHY portion of a GPHY. */
438static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
439{
440
441 might_sleep();
442
443 b43legacy_phy_setupg(dev);
444 if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL)
445 b43legacy_phy_write(dev, 0x046E, 0x03CF);
446}
447
448static void b43legacy_phy_initb2(struct b43legacy_wldev *dev)
449{
450 struct b43legacy_phy *phy = &dev->phy;
451 u16 offset;
452 int val;
453
454 b43legacy_write16(dev, 0x03EC, 0x3F22);
455 b43legacy_phy_write(dev, 0x0020, 0x301C);
456 b43legacy_phy_write(dev, 0x0026, 0x0000);
457 b43legacy_phy_write(dev, 0x0030, 0x00C6);
458 b43legacy_phy_write(dev, 0x0088, 0x3E00);
459 val = 0x3C3D;
460 for (offset = 0x0089; offset < 0x00A7; offset++) {
461 b43legacy_phy_write(dev, offset, val);
462 val -= 0x0202;
463 }
464 b43legacy_phy_write(dev, 0x03E4, 0x3000);
465 if (phy->channel == 0xFF)
466 b43legacy_radio_selectchannel(dev,
467 B43legacy_RADIO_DEFAULT_CHANNEL_BG,
468 0);
469 else
470 b43legacy_radio_selectchannel(dev, phy->channel, 0);
471 if (phy->radio_ver != 0x2050) {
472 b43legacy_radio_write16(dev, 0x0075, 0x0080);
473 b43legacy_radio_write16(dev, 0x0079, 0x0081);
474 }
475 b43legacy_radio_write16(dev, 0x0050, 0x0020);
476 b43legacy_radio_write16(dev, 0x0050, 0x0023);
477 if (phy->radio_ver == 0x2050) {
478 b43legacy_radio_write16(dev, 0x0050, 0x0020);
479 b43legacy_radio_write16(dev, 0x005A, 0x0070);
480 b43legacy_radio_write16(dev, 0x005B, 0x007B);
481 b43legacy_radio_write16(dev, 0x005C, 0x00B0);
482 b43legacy_radio_write16(dev, 0x007A, 0x000F);
483 b43legacy_phy_write(dev, 0x0038, 0x0677);
484 b43legacy_radio_init2050(dev);
485 }
486 b43legacy_phy_write(dev, 0x0014, 0x0080);
487 b43legacy_phy_write(dev, 0x0032, 0x00CA);
488 b43legacy_phy_write(dev, 0x0032, 0x00CC);
489 b43legacy_phy_write(dev, 0x0035, 0x07C2);
490 b43legacy_phy_lo_b_measure(dev);
491 b43legacy_phy_write(dev, 0x0026, 0xCC00);
492 if (phy->radio_ver != 0x2050)
493 b43legacy_phy_write(dev, 0x0026, 0xCE00);
494 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000);
495 b43legacy_phy_write(dev, 0x002A, 0x88A3);
496 if (phy->radio_ver != 0x2050)
497 b43legacy_phy_write(dev, 0x002A, 0x88C2);
498 b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
499 b43legacy_phy_init_pctl(dev);
500}
501
502static void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
503{
504 struct b43legacy_phy *phy = &dev->phy;
505 u16 offset;
506 u16 val;
507
508 b43legacy_write16(dev, 0x03EC, 0x3F22);
509 b43legacy_phy_write(dev, 0x0020, 0x301C);
510 b43legacy_phy_write(dev, 0x0026, 0x0000);
511 b43legacy_phy_write(dev, 0x0030, 0x00C6);
512 b43legacy_phy_write(dev, 0x0088, 0x3E00);
513 val = 0x3C3D;
514 for (offset = 0x0089; offset < 0x00A7; offset++) {
515 b43legacy_phy_write(dev, offset, val);
516 val -= 0x0202;
517 }
518 b43legacy_phy_write(dev, 0x03E4, 0x3000);
519 if (phy->channel == 0xFF)
520 b43legacy_radio_selectchannel(dev,
521 B43legacy_RADIO_DEFAULT_CHANNEL_BG,
522 0);
523 else
524 b43legacy_radio_selectchannel(dev, phy->channel, 0);
525 if (phy->radio_ver != 0x2050) {
526 b43legacy_radio_write16(dev, 0x0075, 0x0080);
527 b43legacy_radio_write16(dev, 0x0079, 0x0081);
528 }
529 b43legacy_radio_write16(dev, 0x0050, 0x0020);
530 b43legacy_radio_write16(dev, 0x0050, 0x0023);
531 if (phy->radio_ver == 0x2050) {
532 b43legacy_radio_write16(dev, 0x0050, 0x0020);
533 b43legacy_radio_write16(dev, 0x005A, 0x0070);
534 b43legacy_radio_write16(dev, 0x005B, 0x007B);
535 b43legacy_radio_write16(dev, 0x005C, 0x00B0);
536 b43legacy_radio_write16(dev, 0x007A, 0x000F);
537 b43legacy_phy_write(dev, 0x0038, 0x0677);
538 b43legacy_radio_init2050(dev);
539 }
540 b43legacy_phy_write(dev, 0x0014, 0x0080);
541 b43legacy_phy_write(dev, 0x0032, 0x00CA);
542 if (phy->radio_ver == 0x2050)
543 b43legacy_phy_write(dev, 0x0032, 0x00E0);
544 b43legacy_phy_write(dev, 0x0035, 0x07C2);
545
546 b43legacy_phy_lo_b_measure(dev);
547
548 b43legacy_phy_write(dev, 0x0026, 0xCC00);
549 if (phy->radio_ver == 0x2050)
550 b43legacy_phy_write(dev, 0x0026, 0xCE00);
551 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100);
552 b43legacy_phy_write(dev, 0x002A, 0x88A3);
553 if (phy->radio_ver == 0x2050)
554 b43legacy_phy_write(dev, 0x002A, 0x88C2);
555 b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
556 if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
557 b43legacy_calc_nrssi_slope(dev);
558 b43legacy_calc_nrssi_threshold(dev);
559 }
560 b43legacy_phy_init_pctl(dev);
561}
562
563static void b43legacy_phy_initb5(struct b43legacy_wldev *dev)
564{
565 struct b43legacy_phy *phy = &dev->phy;
566 u16 offset;
567 u16 value;
568 u8 old_channel;
569
570 if (phy->analog == 1)
571 b43legacy_radio_write16(dev, 0x007A,
572 b43legacy_radio_read16(dev, 0x007A)
573 | 0x0050);
574 if (!is_bcm_board_vendor(dev) &&
575 (dev->dev->bus->boardinfo.type != 0x0416)) {
576 value = 0x2120;
577 for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
578 b43legacy_phy_write(dev, offset, value);
579 value += 0x0202;
580 }
581 }
582 b43legacy_phy_write(dev, 0x0035,
583 (b43legacy_phy_read(dev, 0x0035) & 0xF0FF)
584 | 0x0700);
585 if (phy->radio_ver == 0x2050)
586 b43legacy_phy_write(dev, 0x0038, 0x0667);
587
588 if (phy->gmode) {
589 if (phy->radio_ver == 0x2050) {
590 b43legacy_radio_write16(dev, 0x007A,
591 b43legacy_radio_read16(dev, 0x007A)
592 | 0x0020);
593 b43legacy_radio_write16(dev, 0x0051,
594 b43legacy_radio_read16(dev, 0x0051)
595 | 0x0004);
596 }
597 b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000);
598
599 b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802)
600 | 0x0100);
601 b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B)
602 | 0x2000);
603
604 b43legacy_phy_write(dev, 0x001C, 0x186A);
605
606 b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev,
607 0x0013) & 0x00FF) | 0x1900);
608 b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev,
609 0x0035) & 0xFFC0) | 0x0064);
610 b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
611 0x005D) & 0xFF80) | 0x000A);
612 }
613
614 if (dev->bad_frames_preempt)
615 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
616 b43legacy_phy_read(dev,
617 B43legacy_PHY_RADIO_BITFIELD) | (1 << 11));
618
619 if (phy->analog == 1) {
620 b43legacy_phy_write(dev, 0x0026, 0xCE00);
621 b43legacy_phy_write(dev, 0x0021, 0x3763);
622 b43legacy_phy_write(dev, 0x0022, 0x1BC3);
623 b43legacy_phy_write(dev, 0x0023, 0x06F9);
624 b43legacy_phy_write(dev, 0x0024, 0x037E);
625 } else
626 b43legacy_phy_write(dev, 0x0026, 0xCC00);
627 b43legacy_phy_write(dev, 0x0030, 0x00C6);
628 b43legacy_write16(dev, 0x03EC, 0x3F22);
629
630 if (phy->analog == 1)
631 b43legacy_phy_write(dev, 0x0020, 0x3E1C);
632 else
633 b43legacy_phy_write(dev, 0x0020, 0x301C);
634
635 if (phy->analog == 0)
636 b43legacy_write16(dev, 0x03E4, 0x3000);
637
638 old_channel = (phy->channel == 0xFF) ? 1 : phy->channel;
639 /* Force to channel 7, even if not supported. */
640 b43legacy_radio_selectchannel(dev, 7, 0);
641
642 if (phy->radio_ver != 0x2050) {
643 b43legacy_radio_write16(dev, 0x0075, 0x0080);
644 b43legacy_radio_write16(dev, 0x0079, 0x0081);
645 }
646
647 b43legacy_radio_write16(dev, 0x0050, 0x0020);
648 b43legacy_radio_write16(dev, 0x0050, 0x0023);
649
650 if (phy->radio_ver == 0x2050) {
651 b43legacy_radio_write16(dev, 0x0050, 0x0020);
652 b43legacy_radio_write16(dev, 0x005A, 0x0070);
653 }
654
655 b43legacy_radio_write16(dev, 0x005B, 0x007B);
656 b43legacy_radio_write16(dev, 0x005C, 0x00B0);
657
658 b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev,
659 0x007A) | 0x0007);
660
661 b43legacy_radio_selectchannel(dev, old_channel, 0);
662
663 b43legacy_phy_write(dev, 0x0014, 0x0080);
664 b43legacy_phy_write(dev, 0x0032, 0x00CA);
665 b43legacy_phy_write(dev, 0x002A, 0x88A3);
666
667 b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
668
669 if (phy->radio_ver == 0x2050)
670 b43legacy_radio_write16(dev, 0x005D, 0x000D);
671
672 b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) &
673 0xFFC0) | 0x0004);
674}
675
676static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
677{
678 struct b43legacy_phy *phy = &dev->phy;
679 u16 offset;
680 u16 val;
681 u8 old_channel;
682
683 b43legacy_phy_write(dev, 0x003E, 0x817A);
684 b43legacy_radio_write16(dev, 0x007A,
685 (b43legacy_radio_read16(dev, 0x007A) | 0x0058));
686 if (phy->radio_rev == 4 ||
687 phy->radio_rev == 5) {
688 b43legacy_radio_write16(dev, 0x0051, 0x0037);
689 b43legacy_radio_write16(dev, 0x0052, 0x0070);
690 b43legacy_radio_write16(dev, 0x0053, 0x00B3);
691 b43legacy_radio_write16(dev, 0x0054, 0x009B);
692 b43legacy_radio_write16(dev, 0x005A, 0x0088);
693 b43legacy_radio_write16(dev, 0x005B, 0x0088);
694 b43legacy_radio_write16(dev, 0x005D, 0x0088);
695 b43legacy_radio_write16(dev, 0x005E, 0x0088);
696 b43legacy_radio_write16(dev, 0x007D, 0x0088);
697 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
698 B43legacy_UCODEFLAGS_OFFSET,
699 (b43legacy_shm_read32(dev,
700 B43legacy_SHM_SHARED,
701 B43legacy_UCODEFLAGS_OFFSET)
702 | 0x00000200));
703 }
704 if (phy->radio_rev == 8) {
705 b43legacy_radio_write16(dev, 0x0051, 0x0000);
706 b43legacy_radio_write16(dev, 0x0052, 0x0040);
707 b43legacy_radio_write16(dev, 0x0053, 0x00B7);
708 b43legacy_radio_write16(dev, 0x0054, 0x0098);
709 b43legacy_radio_write16(dev, 0x005A, 0x0088);
710 b43legacy_radio_write16(dev, 0x005B, 0x006B);
711 b43legacy_radio_write16(dev, 0x005C, 0x000F);
712 if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) {
713 b43legacy_radio_write16(dev, 0x005D, 0x00FA);
714 b43legacy_radio_write16(dev, 0x005E, 0x00D8);
715 } else {
716 b43legacy_radio_write16(dev, 0x005D, 0x00F5);
717 b43legacy_radio_write16(dev, 0x005E, 0x00B8);
718 }
719 b43legacy_radio_write16(dev, 0x0073, 0x0003);
720 b43legacy_radio_write16(dev, 0x007D, 0x00A8);
721 b43legacy_radio_write16(dev, 0x007C, 0x0001);
722 b43legacy_radio_write16(dev, 0x007E, 0x0008);
723 }
724 val = 0x1E1F;
725 for (offset = 0x0088; offset < 0x0098; offset++) {
726 b43legacy_phy_write(dev, offset, val);
727 val -= 0x0202;
728 }
729 val = 0x3E3F;
730 for (offset = 0x0098; offset < 0x00A8; offset++) {
731 b43legacy_phy_write(dev, offset, val);
732 val -= 0x0202;
733 }
734 val = 0x2120;
735 for (offset = 0x00A8; offset < 0x00C8; offset++) {
736 b43legacy_phy_write(dev, offset, (val & 0x3F3F));
737 val += 0x0202;
738 }
739 if (phy->type == B43legacy_PHYTYPE_G) {
740 b43legacy_radio_write16(dev, 0x007A,
741 b43legacy_radio_read16(dev, 0x007A) |
742 0x0020);
743 b43legacy_radio_write16(dev, 0x0051,
744 b43legacy_radio_read16(dev, 0x0051) |
745 0x0004);
746 b43legacy_phy_write(dev, 0x0802,
747 b43legacy_phy_read(dev, 0x0802) | 0x0100);
748 b43legacy_phy_write(dev, 0x042B,
749 b43legacy_phy_read(dev, 0x042B) | 0x2000);
750 b43legacy_phy_write(dev, 0x5B, 0x0000);
751 b43legacy_phy_write(dev, 0x5C, 0x0000);
752 }
753
754 old_channel = phy->channel;
755 if (old_channel >= 8)
756 b43legacy_radio_selectchannel(dev, 1, 0);
757 else
758 b43legacy_radio_selectchannel(dev, 13, 0);
759
760 b43legacy_radio_write16(dev, 0x0050, 0x0020);
761 b43legacy_radio_write16(dev, 0x0050, 0x0023);
762 udelay(40);
763 if (phy->radio_rev < 6 || phy->radio_rev == 8) {
764 b43legacy_radio_write16(dev, 0x007C,
765 (b43legacy_radio_read16(dev, 0x007C)
766 | 0x0002));
767 b43legacy_radio_write16(dev, 0x0050, 0x0020);
768 }
769 if (phy->radio_rev <= 2) {
770 b43legacy_radio_write16(dev, 0x007C, 0x0020);
771 b43legacy_radio_write16(dev, 0x005A, 0x0070);
772 b43legacy_radio_write16(dev, 0x005B, 0x007B);
773 b43legacy_radio_write16(dev, 0x005C, 0x00B0);
774 }
775 b43legacy_radio_write16(dev, 0x007A,
776 (b43legacy_radio_read16(dev,
777 0x007A) & 0x00F8) | 0x0007);
778
779 b43legacy_radio_selectchannel(dev, old_channel, 0);
780
781 b43legacy_phy_write(dev, 0x0014, 0x0200);
782 if (phy->radio_rev >= 6)
783 b43legacy_phy_write(dev, 0x002A, 0x88C2);
784 else
785 b43legacy_phy_write(dev, 0x002A, 0x8AC0);
786 b43legacy_phy_write(dev, 0x0038, 0x0668);
787 b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
788 if (phy->radio_rev <= 5)
789 b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
790 0x005D) & 0xFF80) | 0x0003);
791 if (phy->radio_rev <= 2)
792 b43legacy_radio_write16(dev, 0x005D, 0x000D);
793
794 if (phy->analog == 4) {
795 b43legacy_write16(dev, 0x03E4, 0x0009);
796 b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61)
797 & 0xFFF);
798 } else
799 b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev,
800 0x0002) & 0xFFC0) | 0x0004);
801 if (phy->type == B43legacy_PHYTYPE_G)
802 b43legacy_write16(dev, 0x03E6, 0x0);
803 if (phy->type == B43legacy_PHYTYPE_B) {
804 b43legacy_write16(dev, 0x03E6, 0x8140);
805 b43legacy_phy_write(dev, 0x0016, 0x0410);
806 b43legacy_phy_write(dev, 0x0017, 0x0820);
807 b43legacy_phy_write(dev, 0x0062, 0x0007);
808 b43legacy_radio_init2050(dev);
809 b43legacy_phy_lo_g_measure(dev);
810 if (dev->dev->bus->sprom.r1.boardflags_lo &
811 B43legacy_BFL_RSSI) {
812 b43legacy_calc_nrssi_slope(dev);
813 b43legacy_calc_nrssi_threshold(dev);
814 }
815 b43legacy_phy_init_pctl(dev);
816 }
817}
818
819static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
820{
821 struct b43legacy_phy *phy = &dev->phy;
822 u16 backup_phy[15] = {0};
823 u16 backup_radio[3];
824 u16 backup_bband;
825 u16 i;
826 u16 loop1_cnt;
827 u16 loop1_done;
828 u16 loop1_omitted;
829 u16 loop2_done;
830
831 backup_phy[0] = b43legacy_phy_read(dev, 0x0429);
832 backup_phy[1] = b43legacy_phy_read(dev, 0x0001);
833 backup_phy[2] = b43legacy_phy_read(dev, 0x0811);
834 backup_phy[3] = b43legacy_phy_read(dev, 0x0812);
835 if (phy->rev != 1) {
836 backup_phy[4] = b43legacy_phy_read(dev, 0x0814);
837 backup_phy[5] = b43legacy_phy_read(dev, 0x0815);
838 }
839 backup_phy[6] = b43legacy_phy_read(dev, 0x005A);
840 backup_phy[7] = b43legacy_phy_read(dev, 0x0059);
841 backup_phy[8] = b43legacy_phy_read(dev, 0x0058);
842 backup_phy[9] = b43legacy_phy_read(dev, 0x000A);
843 backup_phy[10] = b43legacy_phy_read(dev, 0x0003);
844 backup_phy[11] = b43legacy_phy_read(dev, 0x080F);
845 backup_phy[12] = b43legacy_phy_read(dev, 0x0810);
846 backup_phy[13] = b43legacy_phy_read(dev, 0x002B);
847 backup_phy[14] = b43legacy_phy_read(dev, 0x0015);
848 b43legacy_phy_read(dev, 0x002D); /* dummy read */
849 backup_bband = phy->bbatt;
850 backup_radio[0] = b43legacy_radio_read16(dev, 0x0052);
851 backup_radio[1] = b43legacy_radio_read16(dev, 0x0043);
852 backup_radio[2] = b43legacy_radio_read16(dev, 0x007A);
853
854 b43legacy_phy_write(dev, 0x0429,
855 b43legacy_phy_read(dev, 0x0429) & 0x3FFF);
856 b43legacy_phy_write(dev, 0x0001,
857 b43legacy_phy_read(dev, 0x0001) & 0x8000);
858 b43legacy_phy_write(dev, 0x0811,
859 b43legacy_phy_read(dev, 0x0811) | 0x0002);
860 b43legacy_phy_write(dev, 0x0812,
861 b43legacy_phy_read(dev, 0x0812) & 0xFFFD);
862 b43legacy_phy_write(dev, 0x0811,
863 b43legacy_phy_read(dev, 0x0811) | 0x0001);
864 b43legacy_phy_write(dev, 0x0812,
865 b43legacy_phy_read(dev, 0x0812) & 0xFFFE);
866 if (phy->rev != 1) {
867 b43legacy_phy_write(dev, 0x0814,
868 b43legacy_phy_read(dev, 0x0814) | 0x0001);
869 b43legacy_phy_write(dev, 0x0815,
870 b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
871 b43legacy_phy_write(dev, 0x0814,
872 b43legacy_phy_read(dev, 0x0814) | 0x0002);
873 b43legacy_phy_write(dev, 0x0815,
874 b43legacy_phy_read(dev, 0x0815) & 0xFFFD);
875 }
876 b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) |
877 0x000C);
878 b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) |
879 0x000C);
880
881 b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811)
882 & 0xFFCF) | 0x0030);
883 b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812)
884 & 0xFFCF) | 0x0010);
885
886 b43legacy_phy_write(dev, 0x005A, 0x0780);
887 b43legacy_phy_write(dev, 0x0059, 0xC810);
888 b43legacy_phy_write(dev, 0x0058, 0x000D);
889 if (phy->analog == 0)
890 b43legacy_phy_write(dev, 0x0003, 0x0122);
891 else
892 b43legacy_phy_write(dev, 0x000A,
893 b43legacy_phy_read(dev, 0x000A)
894 | 0x2000);
895 if (phy->rev != 1) {
896 b43legacy_phy_write(dev, 0x0814,
897 b43legacy_phy_read(dev, 0x0814) | 0x0004);
898 b43legacy_phy_write(dev, 0x0815,
899 b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
900 }
901 b43legacy_phy_write(dev, 0x0003,
902 (b43legacy_phy_read(dev, 0x0003)
903 & 0xFF9F) | 0x0040);
904 if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) {
905 b43legacy_radio_write16(dev, 0x0052, 0x0000);
906 b43legacy_radio_write16(dev, 0x0043,
907 (b43legacy_radio_read16(dev, 0x0043)
908 & 0xFFF0) | 0x0009);
909 loop1_cnt = 9;
910 } else if (phy->radio_rev == 8) {
911 b43legacy_radio_write16(dev, 0x0043, 0x000F);
912 loop1_cnt = 15;
913 } else
914 loop1_cnt = 0;
915
916 b43legacy_phy_set_baseband_attenuation(dev, 11);
917
918 if (phy->rev >= 3)
919 b43legacy_phy_write(dev, 0x080F, 0xC020);
920 else
921 b43legacy_phy_write(dev, 0x080F, 0x8020);
922 b43legacy_phy_write(dev, 0x0810, 0x0000);
923
924 b43legacy_phy_write(dev, 0x002B,
925 (b43legacy_phy_read(dev, 0x002B)
926 & 0xFFC0) | 0x0001);
927 b43legacy_phy_write(dev, 0x002B,
928 (b43legacy_phy_read(dev, 0x002B)
929 & 0xC0FF) | 0x0800);
930 b43legacy_phy_write(dev, 0x0811,
931 b43legacy_phy_read(dev, 0x0811) | 0x0100);
932 b43legacy_phy_write(dev, 0x0812,
933 b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
934 if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) {
935 if (phy->rev >= 7) {
936 b43legacy_phy_write(dev, 0x0811,
937 b43legacy_phy_read(dev, 0x0811)
938 | 0x0800);
939 b43legacy_phy_write(dev, 0x0812,
940 b43legacy_phy_read(dev, 0x0812)
941 | 0x8000);
942 }
943 }
944 b43legacy_radio_write16(dev, 0x007A,
945 b43legacy_radio_read16(dev, 0x007A)
946 & 0x00F7);
947
948 for (i = 0; i < loop1_cnt; i++) {
949 b43legacy_radio_write16(dev, 0x0043, loop1_cnt);
950 b43legacy_phy_write(dev, 0x0812,
951 (b43legacy_phy_read(dev, 0x0812)
952 & 0xF0FF) | (i << 8));
953 b43legacy_phy_write(dev, 0x0015,
954 (b43legacy_phy_read(dev, 0x0015)
955 & 0x0FFF) | 0xA000);
956 b43legacy_phy_write(dev, 0x0015,
957 (b43legacy_phy_read(dev, 0x0015)
958 & 0x0FFF) | 0xF000);
959 udelay(20);
960 if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
961 break;
962 }
963 loop1_done = i;
964 loop1_omitted = loop1_cnt - loop1_done;
965
966 loop2_done = 0;
967 if (loop1_done >= 8) {
968 b43legacy_phy_write(dev, 0x0812,
969 b43legacy_phy_read(dev, 0x0812)
970 | 0x0030);
971 for (i = loop1_done - 8; i < 16; i++) {
972 b43legacy_phy_write(dev, 0x0812,
973 (b43legacy_phy_read(dev, 0x0812)
974 & 0xF0FF) | (i << 8));
975 b43legacy_phy_write(dev, 0x0015,
976 (b43legacy_phy_read(dev, 0x0015)
977 & 0x0FFF) | 0xA000);
978 b43legacy_phy_write(dev, 0x0015,
979 (b43legacy_phy_read(dev, 0x0015)
980 & 0x0FFF) | 0xF000);
981 udelay(20);
982 if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
983 break;
984 }
985 }
986
987 if (phy->rev != 1) {
988 b43legacy_phy_write(dev, 0x0814, backup_phy[4]);
989 b43legacy_phy_write(dev, 0x0815, backup_phy[5]);
990 }
991 b43legacy_phy_write(dev, 0x005A, backup_phy[6]);
992 b43legacy_phy_write(dev, 0x0059, backup_phy[7]);
993 b43legacy_phy_write(dev, 0x0058, backup_phy[8]);
994 b43legacy_phy_write(dev, 0x000A, backup_phy[9]);
995 b43legacy_phy_write(dev, 0x0003, backup_phy[10]);
996 b43legacy_phy_write(dev, 0x080F, backup_phy[11]);
997 b43legacy_phy_write(dev, 0x0810, backup_phy[12]);
998 b43legacy_phy_write(dev, 0x002B, backup_phy[13]);
999 b43legacy_phy_write(dev, 0x0015, backup_phy[14]);
1000
1001 b43legacy_phy_set_baseband_attenuation(dev, backup_bband);
1002
1003 b43legacy_radio_write16(dev, 0x0052, backup_radio[0]);
1004 b43legacy_radio_write16(dev, 0x0043, backup_radio[1]);
1005 b43legacy_radio_write16(dev, 0x007A, backup_radio[2]);
1006
1007 b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003);
1008 udelay(10);
1009 b43legacy_phy_write(dev, 0x0811, backup_phy[2]);
1010 b43legacy_phy_write(dev, 0x0812, backup_phy[3]);
1011 b43legacy_phy_write(dev, 0x0429, backup_phy[0]);
1012 b43legacy_phy_write(dev, 0x0001, backup_phy[1]);
1013
1014 phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
1015 phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
1016}
1017
1018static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
1019{
1020 struct b43legacy_phy *phy = &dev->phy;
1021 u16 tmp;
1022
1023 if (phy->rev == 1)
1024 b43legacy_phy_initb5(dev);
1025 else
1026 b43legacy_phy_initb6(dev);
1027 if (phy->rev >= 2 || phy->gmode)
1028 b43legacy_phy_inita(dev);
1029
1030 if (phy->rev >= 2) {
1031 b43legacy_phy_write(dev, 0x0814, 0x0000);
1032 b43legacy_phy_write(dev, 0x0815, 0x0000);
1033 }
1034 if (phy->rev == 2) {
1035 b43legacy_phy_write(dev, 0x0811, 0x0000);
1036 b43legacy_phy_write(dev, 0x0015, 0x00C0);
1037 }
1038 if (phy->rev > 5) {
1039 b43legacy_phy_write(dev, 0x0811, 0x0400);
1040 b43legacy_phy_write(dev, 0x0015, 0x00C0);
1041 }
1042 if (phy->rev >= 2 || phy->gmode) {
1043 tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
1044 if (tmp == 3 || tmp == 5) {
1045 b43legacy_phy_write(dev, 0x04C2, 0x1816);
1046 b43legacy_phy_write(dev, 0x04C3, 0x8006);
1047 if (tmp == 5)
1048 b43legacy_phy_write(dev, 0x04CC,
1049 (b43legacy_phy_read(dev,
1050 0x04CC) & 0x00FF) |
1051 0x1F00);
1052 }
1053 b43legacy_phy_write(dev, 0x047E, 0x0078);
1054 }
1055 if (phy->radio_rev == 8) {
1056 b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
1057 | 0x0080);
1058 b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E)
1059 | 0x0004);
1060 }
1061 if (phy->rev >= 2 && phy->gmode)
1062 b43legacy_calc_loopback_gain(dev);
1063 if (phy->radio_rev != 8) {
1064 if (phy->initval == 0xFFFF)
1065 phy->initval = b43legacy_radio_init2050(dev);
1066 else
1067 b43legacy_radio_write16(dev, 0x0078, phy->initval);
1068 }
1069 if (phy->txctl2 == 0xFFFF)
1070 b43legacy_phy_lo_g_measure(dev);
1071 else {
1072 if (phy->radio_ver == 0x2050 && phy->radio_rev == 8)
1073 b43legacy_radio_write16(dev, 0x0052,
1074 (phy->txctl1 << 4) |
1075 phy->txctl2);
1076 else
1077 b43legacy_radio_write16(dev, 0x0052,
1078 (b43legacy_radio_read16(dev,
1079 0x0052) & 0xFFF0) |
1080 phy->txctl1);
1081 if (phy->rev >= 6)
1082 b43legacy_phy_write(dev, 0x0036,
1083 (b43legacy_phy_read(dev, 0x0036)
1084 & 0x0FFF) | (phy->txctl2 << 12));
1085 if (dev->dev->bus->sprom.r1.boardflags_lo &
1086 B43legacy_BFL_PACTRL)
1087 b43legacy_phy_write(dev, 0x002E, 0x8075);
1088 else
1089 b43legacy_phy_write(dev, 0x002E, 0x807F);
1090 if (phy->rev < 2)
1091 b43legacy_phy_write(dev, 0x002F, 0x0101);
1092 else
1093 b43legacy_phy_write(dev, 0x002F, 0x0202);
1094 }
1095 if (phy->gmode || phy->rev >= 2) {
1096 b43legacy_phy_lo_adjust(dev, 0);
1097 b43legacy_phy_write(dev, 0x080F, 0x8078);
1098 }
1099
1100 if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) {
1101 /* The specs state to update the NRSSI LT with
1102 * the value 0x7FFFFFFF here. I think that is some weird
1103 * compiler optimization in the original driver.
1104 * Essentially, what we do here is resetting all NRSSI LT
1105 * entries to -32 (see the limit_value() in nrssi_hw_update())
1106 */
1107 b43legacy_nrssi_hw_update(dev, 0xFFFF);
1108 b43legacy_calc_nrssi_threshold(dev);
1109 } else if (phy->gmode || phy->rev >= 2) {
1110 if (phy->nrssi[0] == -1000) {
1111 B43legacy_WARN_ON(phy->nrssi[1] != -1000);
1112 b43legacy_calc_nrssi_slope(dev);
1113 } else {
1114 B43legacy_WARN_ON(phy->nrssi[1] == -1000);
1115 b43legacy_calc_nrssi_threshold(dev);
1116 }
1117 }
1118 if (phy->radio_rev == 8)
1119 b43legacy_phy_write(dev, 0x0805, 0x3230);
1120 b43legacy_phy_init_pctl(dev);
1121 if (dev->dev->bus->chip_id == 0x4306
1122 && dev->dev->bus->chip_package == 2) {
1123 b43legacy_phy_write(dev, 0x0429,
1124 b43legacy_phy_read(dev, 0x0429) & 0xBFFF);
1125 b43legacy_phy_write(dev, 0x04C3,
1126 b43legacy_phy_read(dev, 0x04C3) & 0x7FFF);
1127 }
1128}
1129
1130static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev)
1131{
1132 int i;
1133 u16 ret = 0;
1134 unsigned long flags;
1135
1136 local_irq_save(flags);
1137 for (i = 0; i < 10; i++) {
1138 b43legacy_phy_write(dev, 0x0015, 0xAFA0);
1139 udelay(1);
1140 b43legacy_phy_write(dev, 0x0015, 0xEFA0);
1141 udelay(10);
1142 b43legacy_phy_write(dev, 0x0015, 0xFFA0);
1143 udelay(40);
1144 ret += b43legacy_phy_read(dev, 0x002C);
1145 }
1146 local_irq_restore(flags);
1147 b43legacy_voluntary_preempt();
1148
1149 return ret;
1150}
1151
1152void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev)
1153{
1154 struct b43legacy_phy *phy = &dev->phy;
1155 u16 regstack[12] = { 0 };
1156 u16 mls;
1157 u16 fval;
1158 int i;
1159 int j;
1160
1161 regstack[0] = b43legacy_phy_read(dev, 0x0015);
1162 regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0;
1163
1164 if (phy->radio_ver == 0x2053) {
1165 regstack[2] = b43legacy_phy_read(dev, 0x000A);
1166 regstack[3] = b43legacy_phy_read(dev, 0x002A);
1167 regstack[4] = b43legacy_phy_read(dev, 0x0035);
1168 regstack[5] = b43legacy_phy_read(dev, 0x0003);
1169 regstack[6] = b43legacy_phy_read(dev, 0x0001);
1170 regstack[7] = b43legacy_phy_read(dev, 0x0030);
1171
1172 regstack[8] = b43legacy_radio_read16(dev, 0x0043);
1173 regstack[9] = b43legacy_radio_read16(dev, 0x007A);
1174 regstack[10] = b43legacy_read16(dev, 0x03EC);
1175 regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0;
1176
1177 b43legacy_phy_write(dev, 0x0030, 0x00FF);
1178 b43legacy_write16(dev, 0x03EC, 0x3F3F);
1179 b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
1180 b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
1181 }
1182 b43legacy_phy_write(dev, 0x0015, 0xB000);
1183 b43legacy_phy_write(dev, 0x002B, 0x0004);
1184
1185 if (phy->radio_ver == 0x2053) {
1186 b43legacy_phy_write(dev, 0x002B, 0x0203);
1187 b43legacy_phy_write(dev, 0x002A, 0x08A3);
1188 }
1189
1190 phy->minlowsig[0] = 0xFFFF;
1191
1192 for (i = 0; i < 4; i++) {
1193 b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
1194 b43legacy_phy_lo_b_r15_loop(dev);
1195 }
1196 for (i = 0; i < 10; i++) {
1197 b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
1198 mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
1199 if (mls < phy->minlowsig[0]) {
1200 phy->minlowsig[0] = mls;
1201 phy->minlowsigpos[0] = i;
1202 }
1203 }
1204 b43legacy_radio_write16(dev, 0x0052, regstack[1]
1205 | phy->minlowsigpos[0]);
1206
1207 phy->minlowsig[1] = 0xFFFF;
1208
1209 for (i = -4; i < 5; i += 2) {
1210 for (j = -4; j < 5; j += 2) {
1211 if (j < 0)
1212 fval = (0x0100 * i) + j + 0x0100;
1213 else
1214 fval = (0x0100 * i) + j;
1215 b43legacy_phy_write(dev, 0x002F, fval);
1216 mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
1217 if (mls < phy->minlowsig[1]) {
1218 phy->minlowsig[1] = mls;
1219 phy->minlowsigpos[1] = fval;
1220 }
1221 }
1222 }
1223 phy->minlowsigpos[1] += 0x0101;
1224
1225 b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
1226 if (phy->radio_ver == 0x2053) {
1227 b43legacy_phy_write(dev, 0x000A, regstack[2]);
1228 b43legacy_phy_write(dev, 0x002A, regstack[3]);
1229 b43legacy_phy_write(dev, 0x0035, regstack[4]);
1230 b43legacy_phy_write(dev, 0x0003, regstack[5]);
1231 b43legacy_phy_write(dev, 0x0001, regstack[6]);
1232 b43legacy_phy_write(dev, 0x0030, regstack[7]);
1233
1234 b43legacy_radio_write16(dev, 0x0043, regstack[8]);
1235 b43legacy_radio_write16(dev, 0x007A, regstack[9]);
1236
1237 b43legacy_radio_write16(dev, 0x0052,
1238 (b43legacy_radio_read16(dev, 0x0052)
1239 & 0x000F) | regstack[11]);
1240
1241 b43legacy_write16(dev, 0x03EC, regstack[10]);
1242 }
1243 b43legacy_phy_write(dev, 0x0015, regstack[0]);
1244}
1245
1246static inline
1247u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev,
1248 u16 control)
1249{
1250 struct b43legacy_phy *phy = &dev->phy;
1251 u16 ret;
1252 unsigned long flags;
1253
1254 local_irq_save(flags);
1255 if (phy->gmode) {
1256 b43legacy_phy_write(dev, 0x15, 0xE300);
1257 control <<= 8;
1258 b43legacy_phy_write(dev, 0x0812, control | 0x00B0);
1259 udelay(5);
1260 b43legacy_phy_write(dev, 0x0812, control | 0x00B2);
1261 udelay(2);
1262 b43legacy_phy_write(dev, 0x0812, control | 0x00B3);
1263 udelay(4);
1264 b43legacy_phy_write(dev, 0x0015, 0xF300);
1265 udelay(8);
1266 } else {
1267 b43legacy_phy_write(dev, 0x0015, control | 0xEFA0);
1268 udelay(2);
1269 b43legacy_phy_write(dev, 0x0015, control | 0xEFE0);
1270 udelay(4);
1271 b43legacy_phy_write(dev, 0x0015, control | 0xFFE0);
1272 udelay(8);
1273 }
1274 ret = b43legacy_phy_read(dev, 0x002D);
1275 local_irq_restore(flags);
1276 b43legacy_voluntary_preempt();
1277
1278 return ret;
1279}
1280
1281static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev,
1282 u16 control)
1283{
1284 int i;
1285 u32 ret = 0;
1286
1287 for (i = 0; i < 8; i++)
1288 ret += b43legacy_phy_lo_g_deviation_subval(dev, control);
1289
1290 return ret;
1291}
1292
1293/* Write the LocalOscillator CONTROL */
1294static inline
1295void b43legacy_lo_write(struct b43legacy_wldev *dev,
1296 struct b43legacy_lopair *pair)
1297{
1298 u16 value;
1299
1300 value = (u8)(pair->low);
1301 value |= ((u8)(pair->high)) << 8;
1302
1303#ifdef CONFIG_B43LEGACY_DEBUG
1304 /* Sanity check. */
1305 if (pair->low < -8 || pair->low > 8 ||
1306 pair->high < -8 || pair->high > 8) {
1307 struct b43legacy_phy *phy = &dev->phy;
1308 b43legacydbg(dev->wl,
1309 "WARNING: Writing invalid LOpair "
1310 "(low: %d, high: %d, index: %lu)\n",
1311 pair->low, pair->high,
1312 (unsigned long)(pair - phy->_lo_pairs));
1313 dump_stack();
1314 }
1315#endif
1316
1317 b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value);
1318}
1319
1320static inline
1321struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev,
1322 u16 bbatt,
1323 u16 rfatt,
1324 u16 tx)
1325{
1326 static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
1327 struct b43legacy_phy *phy = &dev->phy;
1328
1329 if (bbatt > 6)
1330 bbatt = 6;
1331 B43legacy_WARN_ON(rfatt >= 10);
1332
1333 if (tx == 3)
1334 return b43legacy_get_lopair(phy, rfatt, bbatt);
1335 return b43legacy_get_lopair(phy, dict[rfatt], bbatt);
1336}
1337
1338static inline
1339struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev)
1340{
1341 struct b43legacy_phy *phy = &dev->phy;
1342
1343 return b43legacy_find_lopair(dev, phy->bbatt,
1344 phy->rfatt, phy->txctl1);
1345}
1346
1347/* Adjust B/G LO */
1348void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed)
1349{
1350 struct b43legacy_lopair *pair;
1351
1352 if (fixed) {
1353 /* Use fixed values. Only for initialization. */
1354 pair = b43legacy_find_lopair(dev, 2, 3, 0);
1355 } else
1356 pair = b43legacy_current_lopair(dev);
1357 b43legacy_lo_write(dev, pair);
1358}
1359
1360static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev)
1361{
1362 struct b43legacy_phy *phy = &dev->phy;
1363 u16 txctl2 = 0;
1364 u16 i;
1365 u32 smallest;
1366 u32 tmp;
1367
1368 b43legacy_radio_write16(dev, 0x0052, 0x0000);
1369 udelay(10);
1370 smallest = b43legacy_phy_lo_g_singledeviation(dev, 0);
1371 for (i = 0; i < 16; i++) {
1372 b43legacy_radio_write16(dev, 0x0052, i);
1373 udelay(10);
1374 tmp = b43legacy_phy_lo_g_singledeviation(dev, 0);
1375 if (tmp < smallest) {
1376 smallest = tmp;
1377 txctl2 = i;
1378 }
1379 }
1380 phy->txctl2 = txctl2;
1381}
1382
1383static
1384void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev,
1385 const struct b43legacy_lopair *in_pair,
1386 struct b43legacy_lopair *out_pair,
1387 u16 r27)
1388{
1389 static const struct b43legacy_lopair transitions[8] = {
1390 { .high = 1, .low = 1, },
1391 { .high = 1, .low = 0, },
1392 { .high = 1, .low = -1, },
1393 { .high = 0, .low = -1, },
1394 { .high = -1, .low = -1, },
1395 { .high = -1, .low = 0, },
1396 { .high = -1, .low = 1, },
1397 { .high = 0, .low = 1, },
1398 };
1399 struct b43legacy_lopair lowest_transition = {
1400 .high = in_pair->high,
1401 .low = in_pair->low,
1402 };
1403 struct b43legacy_lopair tmp_pair;
1404 struct b43legacy_lopair transition;
1405 int i = 12;
1406 int state = 0;
1407 int found_lower;
1408 int j;
1409 int begin;
1410 int end;
1411 u32 lowest_deviation;
1412 u32 tmp;
1413
1414 /* Note that in_pair and out_pair can point to the same pair.
1415 * Be careful. */
1416
1417 b43legacy_lo_write(dev, &lowest_transition);
1418 lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27);
1419 do {
1420 found_lower = 0;
1421 B43legacy_WARN_ON(!(state >= 0 && state <= 8));
1422 if (state == 0) {
1423 begin = 1;
1424 end = 8;
1425 } else if (state % 2 == 0) {
1426 begin = state - 1;
1427 end = state + 1;
1428 } else {
1429 begin = state - 2;
1430 end = state + 2;
1431 }
1432 if (begin < 1)
1433 begin += 8;
1434 if (end > 8)
1435 end -= 8;
1436
1437 j = begin;
1438 tmp_pair.high = lowest_transition.high;
1439 tmp_pair.low = lowest_transition.low;
1440 while (1) {
1441 B43legacy_WARN_ON(!(j >= 1 && j <= 8));
1442 transition.high = tmp_pair.high +
1443 transitions[j - 1].high;
1444 transition.low = tmp_pair.low + transitions[j - 1].low;
1445 if ((abs(transition.low) < 9)
1446 && (abs(transition.high) < 9)) {
1447 b43legacy_lo_write(dev, &transition);
1448 tmp = b43legacy_phy_lo_g_singledeviation(dev,
1449 r27);
1450 if (tmp < lowest_deviation) {
1451 lowest_deviation = tmp;
1452 state = j;
1453 found_lower = 1;
1454
1455 lowest_transition.high =
1456 transition.high;
1457 lowest_transition.low = transition.low;
1458 }
1459 }
1460 if (j == end)
1461 break;
1462 if (j == 8)
1463 j = 1;
1464 else
1465 j++;
1466 }
1467 } while (i-- && found_lower);
1468
1469 out_pair->high = lowest_transition.high;
1470 out_pair->low = lowest_transition.low;
1471}
1472
1473/* Set the baseband attenuation value on chip. */
1474void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
1475 u16 bbatt)
1476{
1477 struct b43legacy_phy *phy = &dev->phy;
1478 u16 value;
1479
1480 if (phy->analog == 0) {
1481 value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0);
1482 value |= (bbatt & 0x000F);
1483 b43legacy_write16(dev, 0x03E6, value);
1484 return;
1485 }
1486
1487 if (phy->analog > 1) {
1488 value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3;
1489 value |= (bbatt << 2) & 0x003C;
1490 } else {
1491 value = b43legacy_phy_read(dev, 0x0060) & 0xFF87;
1492 value |= (bbatt << 3) & 0x0078;
1493 }
1494 b43legacy_phy_write(dev, 0x0060, value);
1495}
1496
1497/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
1498void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev)
1499{
1500 static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
1501 const int is_initializing = (b43legacy_status(dev)
1502 < B43legacy_STAT_STARTED);
1503 struct b43legacy_phy *phy = &dev->phy;
1504 u16 h;
1505 u16 i;
1506 u16 oldi = 0;
1507 u16 j;
1508 struct b43legacy_lopair control;
1509 struct b43legacy_lopair *tmp_control;
1510 u16 tmp;
1511 u16 regstack[16] = { 0 };
1512 u8 oldchannel;
1513
1514 /* XXX: What are these? */
1515 u8 r27 = 0;
1516 u16 r31;
1517
1518 oldchannel = phy->channel;
1519 /* Setup */
1520 if (phy->gmode) {
1521 regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS);
1522 regstack[1] = b43legacy_phy_read(dev, 0x0802);
1523 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
1524 & 0x7FFF);
1525 b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
1526 }
1527 regstack[3] = b43legacy_read16(dev, 0x03E2);
1528 b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000);
1529 regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1530 regstack[5] = b43legacy_phy_read(dev, 0x15);
1531 regstack[6] = b43legacy_phy_read(dev, 0x2A);
1532 regstack[7] = b43legacy_phy_read(dev, 0x35);
1533 regstack[8] = b43legacy_phy_read(dev, 0x60);
1534 regstack[9] = b43legacy_radio_read16(dev, 0x43);
1535 regstack[10] = b43legacy_radio_read16(dev, 0x7A);
1536 regstack[11] = b43legacy_radio_read16(dev, 0x52);
1537 if (phy->gmode) {
1538 regstack[12] = b43legacy_phy_read(dev, 0x0811);
1539 regstack[13] = b43legacy_phy_read(dev, 0x0812);
1540 regstack[14] = b43legacy_phy_read(dev, 0x0814);
1541 regstack[15] = b43legacy_phy_read(dev, 0x0815);
1542 }
1543 b43legacy_radio_selectchannel(dev, 6, 0);
1544 if (phy->gmode) {
1545 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
1546 & 0x7FFF);
1547 b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
1548 b43legacy_dummy_transmission(dev);
1549 }
1550 b43legacy_radio_write16(dev, 0x0043, 0x0006);
1551
1552 b43legacy_phy_set_baseband_attenuation(dev, 2);
1553
1554 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000);
1555 b43legacy_phy_write(dev, 0x002E, 0x007F);
1556 b43legacy_phy_write(dev, 0x080F, 0x0078);
1557 b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7));
1558 b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0);
1559 b43legacy_phy_write(dev, 0x002B, 0x0203);
1560 b43legacy_phy_write(dev, 0x002A, 0x08A3);
1561 if (phy->gmode) {
1562 b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003);
1563 b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC);
1564 b43legacy_phy_write(dev, 0x0811, 0x01B3);
1565 b43legacy_phy_write(dev, 0x0812, 0x00B2);
1566 }
1567 if (is_initializing)
1568 b43legacy_phy_lo_g_measure_txctl2(dev);
1569 b43legacy_phy_write(dev, 0x080F, 0x8078);
1570
1571 /* Measure */
1572 control.low = 0;
1573 control.high = 0;
1574 for (h = 0; h < 10; h++) {
1575 /* Loop over each possible RadioAttenuation (0-9) */
1576 i = pairorder[h];
1577 if (is_initializing) {
1578 if (i == 3) {
1579 control.low = 0;
1580 control.high = 0;
1581 } else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
1582 ((i % 2 == 0) && (oldi % 2 == 0))) {
1583 tmp_control = b43legacy_get_lopair(phy, oldi,
1584 0);
1585 memcpy(&control, tmp_control, sizeof(control));
1586 } else {
1587 tmp_control = b43legacy_get_lopair(phy, 3, 0);
1588 memcpy(&control, tmp_control, sizeof(control));
1589 }
1590 }
1591 /* Loop over each possible BasebandAttenuation/2 */
1592 for (j = 0; j < 4; j++) {
1593 if (is_initializing) {
1594 tmp = i * 2 + j;
1595 r27 = 0;
1596 r31 = 0;
1597 if (tmp > 14) {
1598 r31 = 1;
1599 if (tmp > 17)
1600 r27 = 1;
1601 if (tmp > 19)
1602 r27 = 2;
1603 }
1604 } else {
1605 tmp_control = b43legacy_get_lopair(phy, i,
1606 j * 2);
1607 if (!tmp_control->used)
1608 continue;
1609 memcpy(&control, tmp_control, sizeof(control));
1610 r27 = 3;
1611 r31 = 0;
1612 }
1613 b43legacy_radio_write16(dev, 0x43, i);
1614 b43legacy_radio_write16(dev, 0x52, phy->txctl2);
1615 udelay(10);
1616 b43legacy_voluntary_preempt();
1617
1618 b43legacy_phy_set_baseband_attenuation(dev, j * 2);
1619
1620 tmp = (regstack[10] & 0xFFF0);
1621 if (r31)
1622 tmp |= 0x0008;
1623 b43legacy_radio_write16(dev, 0x007A, tmp);
1624
1625 tmp_control = b43legacy_get_lopair(phy, i, j * 2);
1626 b43legacy_phy_lo_g_state(dev, &control, tmp_control,
1627 r27);
1628 }
1629 oldi = i;
1630 }
1631 /* Loop over each possible RadioAttenuation (10-13) */
1632 for (i = 10; i < 14; i++) {
1633 /* Loop over each possible BasebandAttenuation/2 */
1634 for (j = 0; j < 4; j++) {
1635 if (is_initializing) {
1636 tmp_control = b43legacy_get_lopair(phy, i - 9,
1637 j * 2);
1638 memcpy(&control, tmp_control, sizeof(control));
1639 /* FIXME: The next line is wrong, as the
1640 * following if statement can never trigger. */
1641 tmp = (i - 9) * 2 + j - 5;
1642 r27 = 0;
1643 r31 = 0;
1644 if (tmp > 14) {
1645 r31 = 1;
1646 if (tmp > 17)
1647 r27 = 1;
1648 if (tmp > 19)
1649 r27 = 2;
1650 }
1651 } else {
1652 tmp_control = b43legacy_get_lopair(phy, i - 9,
1653 j * 2);
1654 if (!tmp_control->used)
1655 continue;
1656 memcpy(&control, tmp_control, sizeof(control));
1657 r27 = 3;
1658 r31 = 0;
1659 }
1660 b43legacy_radio_write16(dev, 0x43, i - 9);
1661 /* FIXME: shouldn't txctl1 be zero in the next line
1662 * and 3 in the loop above? */
1663 b43legacy_radio_write16(dev, 0x52,
1664 phy->txctl2
1665 | (3/*txctl1*/ << 4));
1666 udelay(10);
1667 b43legacy_voluntary_preempt();
1668
1669 b43legacy_phy_set_baseband_attenuation(dev, j * 2);
1670
1671 tmp = (regstack[10] & 0xFFF0);
1672 if (r31)
1673 tmp |= 0x0008;
1674 b43legacy_radio_write16(dev, 0x7A, tmp);
1675
1676 tmp_control = b43legacy_get_lopair(phy, i, j * 2);
1677 b43legacy_phy_lo_g_state(dev, &control, tmp_control,
1678 r27);
1679 }
1680 }
1681
1682 /* Restoration */
1683 if (phy->gmode) {
1684 b43legacy_phy_write(dev, 0x0015, 0xE300);
1685 b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0);
1686 udelay(5);
1687 b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2);
1688 udelay(2);
1689 b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3);
1690 b43legacy_voluntary_preempt();
1691 } else
1692 b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0);
1693 b43legacy_phy_lo_adjust(dev, is_initializing);
1694 b43legacy_phy_write(dev, 0x002E, 0x807F);
1695 if (phy->gmode)
1696 b43legacy_phy_write(dev, 0x002F, 0x0202);
1697 else
1698 b43legacy_phy_write(dev, 0x002F, 0x0101);
1699 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]);
1700 b43legacy_phy_write(dev, 0x0015, regstack[5]);
1701 b43legacy_phy_write(dev, 0x002A, regstack[6]);
1702 b43legacy_phy_write(dev, 0x0035, regstack[7]);
1703 b43legacy_phy_write(dev, 0x0060, regstack[8]);
1704 b43legacy_radio_write16(dev, 0x0043, regstack[9]);
1705 b43legacy_radio_write16(dev, 0x007A, regstack[10]);
1706 regstack[11] &= 0x00F0;
1707 regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F);
1708 b43legacy_radio_write16(dev, 0x52, regstack[11]);
1709 b43legacy_write16(dev, 0x03E2, regstack[3]);
1710 if (phy->gmode) {
1711 b43legacy_phy_write(dev, 0x0811, regstack[12]);
1712 b43legacy_phy_write(dev, 0x0812, regstack[13]);
1713 b43legacy_phy_write(dev, 0x0814, regstack[14]);
1714 b43legacy_phy_write(dev, 0x0815, regstack[15]);
1715 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]);
1716 b43legacy_phy_write(dev, 0x0802, regstack[1]);
1717 }
1718 b43legacy_radio_selectchannel(dev, oldchannel, 1);
1719
1720#ifdef CONFIG_B43LEGACY_DEBUG
1721 {
1722 /* Sanity check for all lopairs. */
1723 for (i = 0; i < B43legacy_LO_COUNT; i++) {
1724 tmp_control = phy->_lo_pairs + i;
1725 if (tmp_control->low < -8 || tmp_control->low > 8 ||
1726 tmp_control->high < -8 || tmp_control->high > 8)
1727 b43legacywarn(dev->wl,
1728 "WARNING: Invalid LOpair (low: %d, high:"
1729 " %d, index: %d)\n",
1730 tmp_control->low, tmp_control->high, i);
1731 }
1732 }
1733#endif /* CONFIG_B43LEGACY_DEBUG */
1734}
1735
1736static
1737void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev)
1738{
1739 struct b43legacy_lopair *pair;
1740
1741 pair = b43legacy_current_lopair(dev);
1742 pair->used = 1;
1743}
1744
1745void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev)
1746{
1747 struct b43legacy_phy *phy = &dev->phy;
1748 struct b43legacy_lopair *pair;
1749 int i;
1750
1751 for (i = 0; i < B43legacy_LO_COUNT; i++) {
1752 pair = phy->_lo_pairs + i;
1753 pair->used = 0;
1754 }
1755}
1756
1757/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
1758 * This function converts a TSSI value to dBm in Q5.2
1759 */
1760static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
1761{
1762 struct b43legacy_phy *phy = &dev->phy;
1763 s8 dbm = 0;
1764 s32 tmp;
1765
1766 tmp = phy->idle_tssi;
1767 tmp += tssi;
1768 tmp -= phy->savedpctlreg;
1769
1770 switch (phy->type) {
1771 case B43legacy_PHYTYPE_B:
1772 case B43legacy_PHYTYPE_G:
1773 tmp = limit_value(tmp, 0x00, 0x3F);
1774 dbm = phy->tssi2dbm[tmp];
1775 break;
1776 default:
1777 B43legacy_BUG_ON(1);
1778 }
1779
1780 return dbm;
1781}
1782
1783/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
1784void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
1785{
1786 struct b43legacy_phy *phy = &dev->phy;
1787 u16 tmp;
1788 u16 txpower;
1789 s8 v0;
1790 s8 v1;
1791 s8 v2;
1792 s8 v3;
1793 s8 average;
1794 int max_pwr;
1795 s16 desired_pwr;
1796 s16 estimated_pwr;
1797 s16 pwr_adjust;
1798 s16 radio_att_delta;
1799 s16 baseband_att_delta;
1800 s16 radio_attenuation;
1801 s16 baseband_attenuation;
1802 unsigned long phylock_flags;
1803
1804 if (phy->savedpctlreg == 0xFFFF)
1805 return;
1806 if ((dev->dev->bus->boardinfo.type == 0x0416) &&
1807 is_bcm_board_vendor(dev))
1808 return;
1809#ifdef CONFIG_B43LEGACY_DEBUG
1810 if (phy->manual_txpower_control)
1811 return;
1812#endif
1813
1814 B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
1815 phy->type == B43legacy_PHYTYPE_G));
1816 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058);
1817 v0 = (s8)(tmp & 0x00FF);
1818 v1 = (s8)((tmp & 0xFF00) >> 8);
1819 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A);
1820 v2 = (s8)(tmp & 0x00FF);
1821 v3 = (s8)((tmp & 0xFF00) >> 8);
1822 tmp = 0;
1823
1824 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
1825 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1826 0x0070);
1827 v0 = (s8)(tmp & 0x00FF);
1828 v1 = (s8)((tmp & 0xFF00) >> 8);
1829 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
1830 0x0072);
1831 v2 = (s8)(tmp & 0x00FF);
1832 v3 = (s8)((tmp & 0xFF00) >> 8);
1833 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
1834 return;
1835 v0 = (v0 + 0x20) & 0x3F;
1836 v1 = (v1 + 0x20) & 0x3F;
1837 v2 = (v2 + 0x20) & 0x3F;
1838 v3 = (v3 + 0x20) & 0x3F;
1839 tmp = 1;
1840 }
1841 b43legacy_radio_clear_tssi(dev);
1842
1843 average = (v0 + v1 + v2 + v3 + 2) / 4;
1844
1845 if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E)
1846 & 0x8))
1847 average -= 13;
1848
1849 estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
1850
1851 max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
1852
1853 if ((dev->dev->bus->sprom.r1.boardflags_lo
1854 & B43legacy_BFL_PACTRL) &&
1855 (phy->type == B43legacy_PHYTYPE_G))
1856 max_pwr -= 0x3;
1857 if (unlikely(max_pwr <= 0)) {
1858 b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
1859 "\n");
1860 max_pwr = 74; /* fake it */
1861 dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
1862 }
1863
1864 /* Use regulatory information to get the maximum power.
1865 * In the absence of such data from mac80211, we will use 20 dBm, which
1866 * is the value for the EU, US, Canada, and most of the world.
1867 * The regulatory maximum is reduced by the antenna gain (from sprom)
1868 * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
1869 * which accounts for the factor of 4 */
1870#define REG_MAX_PWR 20
1871 max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg
1872 - 0x6, max_pwr);
1873
1874 /* find the desired power in Q5.2 - power_level is in dBm
1875 * and limit it - max_pwr is already in Q5.2 */
1876 desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr);
1877 if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
1878 b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
1879 " dBm, Desired TX power output: " Q52_FMT
1880 " dBm\n", Q52_ARG(estimated_pwr),
1881 Q52_ARG(desired_pwr));
1882 /* Check if we need to adjust the current power. The factor of 2 is
1883 * for damping */
1884 pwr_adjust = (desired_pwr - estimated_pwr) / 2;
1885 /* RF attenuation delta
1886 * The minus sign is because lower attenuation => more power */
1887 radio_att_delta = -(pwr_adjust + 7) >> 3;
1888 /* Baseband attenuation delta */
1889 baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
1890 /* Do we need to adjust anything? */
1891 if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
1892 b43legacy_phy_lo_mark_current_used(dev);
1893 return;
1894 }
1895
1896 /* Calculate the new attenuation values. */
1897 baseband_attenuation = phy->bbatt;
1898 baseband_attenuation += baseband_att_delta;
1899 radio_attenuation = phy->rfatt;
1900 radio_attenuation += radio_att_delta;
1901
1902 /* Get baseband and radio attenuation values into permitted ranges.
1903 * baseband 0-11, radio 0-9.
1904 * Radio attenuation affects power level 4 times as much as baseband.
1905 */
1906 if (radio_attenuation < 0) {
1907 baseband_attenuation -= (4 * -radio_attenuation);
1908 radio_attenuation = 0;
1909 } else if (radio_attenuation > 9) {
1910 baseband_attenuation += (4 * (radio_attenuation - 9));
1911 radio_attenuation = 9;
1912 } else {
1913 while (baseband_attenuation < 0 && radio_attenuation > 0) {
1914 baseband_attenuation += 4;
1915 radio_attenuation--;
1916 }
1917 while (baseband_attenuation > 11 && radio_attenuation < 9) {
1918 baseband_attenuation -= 4;
1919 radio_attenuation++;
1920 }
1921 }
1922 baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
1923
1924 txpower = phy->txctl1;
1925 if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
1926 if (radio_attenuation <= 1) {
1927 if (txpower == 0) {
1928 txpower = 3;
1929 radio_attenuation += 2;
1930 baseband_attenuation += 2;
1931 } else if (dev->dev->bus->sprom.r1.boardflags_lo
1932 & B43legacy_BFL_PACTRL) {
1933 baseband_attenuation += 4 *
1934 (radio_attenuation - 2);
1935 radio_attenuation = 2;
1936 }
1937 } else if (radio_attenuation > 4 && txpower != 0) {
1938 txpower = 0;
1939 if (baseband_attenuation < 3) {
1940 radio_attenuation -= 3;
1941 baseband_attenuation += 2;
1942 } else {
1943 radio_attenuation -= 2;
1944 baseband_attenuation -= 2;
1945 }
1946 }
1947 }
1948 /* Save the control values */
1949 phy->txctl1 = txpower;
1950 baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
1951 radio_attenuation = limit_value(radio_attenuation, 0, 9);
1952 phy->rfatt = radio_attenuation;
1953 phy->bbatt = baseband_attenuation;
1954
1955 /* Adjust the hardware */
1956 b43legacy_phy_lock(dev, phylock_flags);
1957 b43legacy_radio_lock(dev);
1958 b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
1959 radio_attenuation, txpower);
1960 b43legacy_phy_lo_mark_current_used(dev);
1961 b43legacy_radio_unlock(dev);
1962 b43legacy_phy_unlock(dev, phylock_flags);
1963}
1964
1965static inline
1966s32 b43legacy_tssi2dbm_ad(s32 num, s32 den)
1967{
1968 if (num < 0)
1969 return num/den;
1970 else
1971 return (num+den/2)/den;
1972}
1973
1974static inline
1975s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
1976{
1977 s32 m1;
1978 s32 m2;
1979 s32 f = 256;
1980 s32 q;
1981 s32 delta;
1982 s8 i = 0;
1983
1984 m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
1985 m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1);
1986 do {
1987 if (i > 15)
1988 return -EINVAL;
1989 q = b43legacy_tssi2dbm_ad(f * 4096 -
1990 b43legacy_tssi2dbm_ad(m2 * f, 16) *
1991 f, 2048);
1992 delta = abs(q - f);
1993 f = q;
1994 i++;
1995 } while (delta >= 2);
1996 entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192),
1997 -127, 128);
1998 return 0;
1999}
2000
2001/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
2002int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
2003{
2004 struct b43legacy_phy *phy = &dev->phy;
2005 s16 pab0;
2006 s16 pab1;
2007 s16 pab2;
2008 u8 idx;
2009 s8 *dyn_tssi2dbm;
2010
2011 B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
2012 phy->type == B43legacy_PHYTYPE_G));
2013 pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0);
2014 pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1);
2015 pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2);
2016
2017 if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
2018 phy->idle_tssi = 0x34;
2019 phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
2020 return 0;
2021 }
2022
2023 if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
2024 pab0 != -1 && pab1 != -1 && pab2 != -1) {
2025 /* The pabX values are set in SPROM. Use them. */
2026 if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 &&
2027 (s8)dev->dev->bus->sprom.r1.itssi_bg != -1)
2028 phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg);
2029 else
2030 phy->idle_tssi = 62;
2031 dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
2032 if (dyn_tssi2dbm == NULL) {
2033 b43legacyerr(dev->wl, "Could not allocate memory"
2034 "for tssi2dbm table\n");
2035 return -ENOMEM;
2036 }
2037 for (idx = 0; idx < 64; idx++)
2038 if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0,
2039 pab1, pab2)) {
2040 phy->tssi2dbm = NULL;
2041 b43legacyerr(dev->wl, "Could not generate "
2042 "tssi2dBm table\n");
2043 kfree(dyn_tssi2dbm);
2044 return -ENODEV;
2045 }
2046 phy->tssi2dbm = dyn_tssi2dbm;
2047 phy->dyn_tssi_tbl = 1;
2048 } else {
2049 /* pabX values not set in SPROM. */
2050 switch (phy->type) {
2051 case B43legacy_PHYTYPE_B:
2052 phy->idle_tssi = 0x34;
2053 phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
2054 break;
2055 case B43legacy_PHYTYPE_G:
2056 phy->idle_tssi = 0x34;
2057 phy->tssi2dbm = b43legacy_tssi2dbm_g_table;
2058 break;
2059 }
2060 }
2061
2062 return 0;
2063}
2064
2065int b43legacy_phy_init(struct b43legacy_wldev *dev)
2066{
2067 struct b43legacy_phy *phy = &dev->phy;
2068 int err = -ENODEV;
2069
2070 switch (phy->type) {
2071 case B43legacy_PHYTYPE_B:
2072 switch (phy->rev) {
2073 case 2:
2074 b43legacy_phy_initb2(dev);
2075 err = 0;
2076 break;
2077 case 4:
2078 b43legacy_phy_initb4(dev);
2079 err = 0;
2080 break;
2081 case 5:
2082 b43legacy_phy_initb5(dev);
2083 err = 0;
2084 break;
2085 case 6:
2086 b43legacy_phy_initb6(dev);
2087 err = 0;
2088 break;
2089 }
2090 break;
2091 case B43legacy_PHYTYPE_G:
2092 b43legacy_phy_initg(dev);
2093 err = 0;
2094 break;
2095 }
2096 if (err)
2097 b43legacyerr(dev->wl, "Unknown PHYTYPE found\n");
2098
2099 return err;
2100}
2101
2102void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev)
2103{
2104 struct b43legacy_phy *phy = &dev->phy;
2105 u16 antennadiv;
2106 u16 offset;
2107 u16 value;
2108 u32 ucodeflags;
2109
2110 antennadiv = phy->antenna_diversity;
2111
2112 if (antennadiv == 0xFFFF)
2113 antennadiv = 3;
2114 B43legacy_WARN_ON(antennadiv > 3);
2115
2116 ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2117 B43legacy_UCODEFLAGS_OFFSET);
2118 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
2119 B43legacy_UCODEFLAGS_OFFSET,
2120 ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV);
2121
2122 switch (phy->type) {
2123 case B43legacy_PHYTYPE_G:
2124 offset = 0x0400;
2125
2126 if (antennadiv == 2)
2127 value = (3/*automatic*/ << 7);
2128 else
2129 value = (antennadiv << 7);
2130 b43legacy_phy_write(dev, offset + 1,
2131 (b43legacy_phy_read(dev, offset + 1)
2132 & 0x7E7F) | value);
2133
2134 if (antennadiv >= 2) {
2135 if (antennadiv == 2)
2136 value = (antennadiv << 7);
2137 else
2138 value = (0/*force0*/ << 7);
2139 b43legacy_phy_write(dev, offset + 0x2B,
2140 (b43legacy_phy_read(dev,
2141 offset + 0x2B)
2142 & 0xFEFF) | value);
2143 }
2144
2145 if (phy->type == B43legacy_PHYTYPE_G) {
2146 if (antennadiv >= 2)
2147 b43legacy_phy_write(dev, 0x048C,
2148 b43legacy_phy_read(dev,
2149 0x048C) | 0x2000);
2150 else
2151 b43legacy_phy_write(dev, 0x048C,
2152 b43legacy_phy_read(dev,
2153 0x048C) & ~0x2000);
2154 if (phy->rev >= 2) {
2155 b43legacy_phy_write(dev, 0x0461,
2156 b43legacy_phy_read(dev,
2157 0x0461) | 0x0010);
2158 b43legacy_phy_write(dev, 0x04AD,
2159 (b43legacy_phy_read(dev,
2160 0x04AD)
2161 & 0x00FF) | 0x0015);
2162 if (phy->rev == 2)
2163 b43legacy_phy_write(dev, 0x0427,
2164 0x0008);
2165 else
2166 b43legacy_phy_write(dev, 0x0427,
2167 (b43legacy_phy_read(dev, 0x0427)
2168 & 0x00FF) | 0x0008);
2169 } else if (phy->rev >= 6)
2170 b43legacy_phy_write(dev, 0x049B, 0x00DC);
2171 } else {
2172 if (phy->rev < 3)
2173 b43legacy_phy_write(dev, 0x002B,
2174 (b43legacy_phy_read(dev,
2175 0x002B) & 0x00FF)
2176 | 0x0024);
2177 else {
2178 b43legacy_phy_write(dev, 0x0061,
2179 b43legacy_phy_read(dev,
2180 0x0061) | 0x0010);
2181 if (phy->rev == 3) {
2182 b43legacy_phy_write(dev, 0x0093,
2183 0x001D);
2184 b43legacy_phy_write(dev, 0x0027,
2185 0x0008);
2186 } else {
2187 b43legacy_phy_write(dev, 0x0093,
2188 0x003A);
2189 b43legacy_phy_write(dev, 0x0027,
2190 (b43legacy_phy_read(dev, 0x0027)
2191 & 0x00FF) | 0x0008);
2192 }
2193 }
2194 }
2195 break;
2196 case B43legacy_PHYTYPE_B:
2197 if (dev->dev->id.revision == 2)
2198 value = (3/*automatic*/ << 7);
2199 else
2200 value = (antennadiv << 7);
2201 b43legacy_phy_write(dev, 0x03E2,
2202 (b43legacy_phy_read(dev, 0x03E2)
2203 & 0xFE7F) | value);
2204 break;
2205 default:
2206 B43legacy_WARN_ON(1);
2207 }
2208
2209 if (antennadiv >= 2) {
2210 ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2211 B43legacy_UCODEFLAGS_OFFSET);
2212 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
2213 B43legacy_UCODEFLAGS_OFFSET,
2214 ucodeflags | B43legacy_UCODEFLAG_AUTODIV);
2215 }
2216
2217 phy->antenna_diversity = antennadiv;
2218}
2219
2220/* Set the PowerSavingControlBits.
2221 * Bitvalues:
2222 * 0 => unset the bit
2223 * 1 => set the bit
2224 * -1 => calculate the bit
2225 */
2226void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
2227 int bit25, int bit26)
2228{
2229 int i;
2230 u32 status;
2231
2232/* FIXME: Force 25 to off and 26 to on for now: */
2233bit25 = 0;
2234bit26 = 1;
2235
2236 if (bit25 == -1) {
2237 /* TODO: If powersave is not off and FIXME is not set and we
2238 * are not in adhoc and thus is not an AP and we arei
2239 * associated, set bit 25 */
2240 }
2241 if (bit26 == -1) {
2242 /* TODO: If the device is awake or this is an AP, or we are
2243 * scanning, or FIXME, or we are associated, or FIXME,
2244 * or the latest PS-Poll packet sent was successful,
2245 * set bit26 */
2246 }
2247 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
2248 if (bit25)
2249 status |= B43legacy_SBF_PS1;
2250 else
2251 status &= ~B43legacy_SBF_PS1;
2252 if (bit26)
2253 status |= B43legacy_SBF_PS2;
2254 else
2255 status &= ~B43legacy_SBF_PS2;
2256 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
2257 if (bit26 && dev->dev->id.revision >= 5) {
2258 for (i = 0; i < 100; i++) {
2259 if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
2260 0x0040) != 4)
2261 break;
2262 udelay(10);
2263 }
2264 }
2265}
diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h
new file mode 100644
index 00000000000..f11b4271714
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.h
@@ -0,0 +1,219 @@
1/*
2
3 Broadcom B43legacy 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 Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
11
12 Some parts of the code in this file are derived from the ipw2200
13 driver Copyright(c) 2003 - 2004 Intel Corporation.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
28 Boston, MA 02110-1301, USA.
29
30*/
31
32#ifndef B43legacy_PHY_H_
33#define B43legacy_PHY_H_
34
35#include <linux/types.h>
36
37enum {
38 B43legacy_ANTENNA0, /* Antenna 0 */
39 B43legacy_ANTENNA1, /* Antenna 0 */
40 B43legacy_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
41 B43legacy_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
42
43 B43legacy_ANTENNA_AUTO = B43legacy_ANTENNA_AUTO0,
44 B43legacy_ANTENNA_DEFAULT = B43legacy_ANTENNA_AUTO,
45};
46
47enum {
48 B43legacy_INTERFMODE_NONE,
49 B43legacy_INTERFMODE_NONWLAN,
50 B43legacy_INTERFMODE_MANUALWLAN,
51 B43legacy_INTERFMODE_AUTOWLAN,
52};
53
54/*** PHY Registers ***/
55
56/* Routing */
57#define B43legacy_PHYROUTE_OFDM_GPHY 0x400
58#define B43legacy_PHYROUTE_EXT_GPHY 0x800
59
60/* Base registers. */
61#define B43legacy_PHY_BASE(reg) (reg)
62/* OFDM (A) registers of a G-PHY */
63#define B43legacy_PHY_OFDM(reg) ((reg) | B43legacy_PHYROUTE_OFDM_GPHY)
64/* Extended G-PHY registers */
65#define B43legacy_PHY_EXTG(reg) ((reg) | B43legacy_PHYROUTE_EXT_GPHY)
66
67
68/* Extended G-PHY Registers */
69#define B43legacy_PHY_CLASSCTL B43legacy_PHY_EXTG(0x02) /* Classify control */
70#define B43legacy_PHY_GTABCTL B43legacy_PHY_EXTG(0x03) /* G-PHY table control (see below) */
71#define B43legacy_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
72#define B43legacy_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
73#define B43legacy_PHY_GTABNR_SHIFT 10
74#define B43legacy_PHY_GTABDATA B43legacy_PHY_EXTG(0x04) /* G-PHY table data */
75#define B43legacy_PHY_LO_MASK B43legacy_PHY_EXTG(0x0F) /* Local Oscillator control mask */
76#define B43legacy_PHY_LO_CTL B43legacy_PHY_EXTG(0x10) /* Local Oscillator control */
77#define B43legacy_PHY_RFOVER B43legacy_PHY_EXTG(0x11) /* RF override */
78#define B43legacy_PHY_RFOVERVAL B43legacy_PHY_EXTG(0x12) /* RF override value */
79/*** OFDM table numbers ***/
80#define B43legacy_OFDMTAB(number, offset) \
81 (((number) << B43legacy_PHY_OTABLENR_SHIFT) \
82 | (offset))
83#define B43legacy_OFDMTAB_AGC1 B43legacy_OFDMTAB(0x00, 0)
84#define B43legacy_OFDMTAB_GAIN0 B43legacy_OFDMTAB(0x00, 0)
85#define B43legacy_OFDMTAB_GAINX B43legacy_OFDMTAB(0x01, 0)
86#define B43legacy_OFDMTAB_GAIN1 B43legacy_OFDMTAB(0x01, 4)
87#define B43legacy_OFDMTAB_AGC3 B43legacy_OFDMTAB(0x02, 0)
88#define B43legacy_OFDMTAB_GAIN2 B43legacy_OFDMTAB(0x02, 3)
89#define B43legacy_OFDMTAB_LNAHPFGAIN1 B43legacy_OFDMTAB(0x03, 0)
90#define B43legacy_OFDMTAB_WRSSI B43legacy_OFDMTAB(0x04, 0)
91#define B43legacy_OFDMTAB_LNAHPFGAIN2 B43legacy_OFDMTAB(0x04, 0)
92#define B43legacy_OFDMTAB_NOISESCALE B43legacy_OFDMTAB(0x05, 0)
93#define B43legacy_OFDMTAB_AGC2 B43legacy_OFDMTAB(0x06, 0)
94#define B43legacy_OFDMTAB_ROTOR B43legacy_OFDMTAB(0x08, 0)
95#define B43legacy_OFDMTAB_ADVRETARD B43legacy_OFDMTAB(0x09, 0)
96#define B43legacy_OFDMTAB_DAC B43legacy_OFDMTAB(0x0C, 0)
97#define B43legacy_OFDMTAB_DC B43legacy_OFDMTAB(0x0E, 7)
98#define B43legacy_OFDMTAB_PWRDYN2 B43legacy_OFDMTAB(0x0E, 12)
99#define B43legacy_OFDMTAB_LNAGAIN B43legacy_OFDMTAB(0x0E, 13)
100
101#define B43legacy_OFDMTAB_LPFGAIN B43legacy_OFDMTAB(0x0F, 12)
102#define B43legacy_OFDMTAB_RSSI B43legacy_OFDMTAB(0x10, 0)
103
104#define B43legacy_OFDMTAB_AGC1_R1 B43legacy_OFDMTAB(0x13, 0)
105#define B43legacy_OFDMTAB_GAINX_R1 B43legacy_OFDMTAB(0x14, 0)
106#define B43legacy_OFDMTAB_MINSIGSQ B43legacy_OFDMTAB(0x14, 1)
107#define B43legacy_OFDMTAB_AGC3_R1 B43legacy_OFDMTAB(0x15, 0)
108#define B43legacy_OFDMTAB_WRSSI_R1 B43legacy_OFDMTAB(0x15, 4)
109#define B43legacy_OFDMTAB_TSSI B43legacy_OFDMTAB(0x15, 0)
110#define B43legacy_OFDMTAB_DACRFPABB B43legacy_OFDMTAB(0x16, 0)
111#define B43legacy_OFDMTAB_DACOFF B43legacy_OFDMTAB(0x17, 0)
112#define B43legacy_OFDMTAB_DCBIAS B43legacy_OFDMTAB(0x18, 0)
113
114void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
115
116/* OFDM (A) PHY Registers */
117#define B43legacy_PHY_VERSION_OFDM B43legacy_PHY_OFDM(0x00) /* Versioning register for A-PHY */
118#define B43legacy_PHY_BBANDCFG B43legacy_PHY_OFDM(0x01) /* Baseband config */
119#define B43legacy_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
120#define B43legacy_PHY_BBANDCFG_RXANT_SHIFT 7
121#define B43legacy_PHY_PWRDOWN B43legacy_PHY_OFDM(0x03) /* Powerdown */
122#define B43legacy_PHY_CRSTHRES1 B43legacy_PHY_OFDM(0x06) /* CRS Threshold 1 */
123#define B43legacy_PHY_LNAHPFCTL B43legacy_PHY_OFDM(0x1C) /* LNA/HPF control */
124#define B43legacy_PHY_ADIVRELATED B43legacy_PHY_OFDM(0x27) /* FIXME rename */
125#define B43legacy_PHY_CRS0 B43legacy_PHY_OFDM(0x29)
126#define B43legacy_PHY_ANTDWELL B43legacy_PHY_OFDM(0x2B) /* Antenna dwell */
127#define B43legacy_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
128#define B43legacy_PHY_ENCORE B43legacy_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
129#define B43legacy_PHY_ENCORE_EN 0x0200 /* Encore enable */
130#define B43legacy_PHY_LMS B43legacy_PHY_OFDM(0x55)
131#define B43legacy_PHY_OFDM61 B43legacy_PHY_OFDM(0x61) /* FIXME rename */
132#define B43legacy_PHY_OFDM61_10 0x0010 /* FIXME rename */
133#define B43legacy_PHY_IQBAL B43legacy_PHY_OFDM(0x69) /* I/Q balance */
134#define B43legacy_PHY_OTABLECTL B43legacy_PHY_OFDM(0x72) /* OFDM table control (see below) */
135#define B43legacy_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
136#define B43legacy_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
137#define B43legacy_PHY_OTABLENR_SHIFT 10
138#define B43legacy_PHY_OTABLEI B43legacy_PHY_OFDM(0x73) /* OFDM table data I */
139#define B43legacy_PHY_OTABLEQ B43legacy_PHY_OFDM(0x74) /* OFDM table data Q */
140#define B43legacy_PHY_HPWR_TSSICTL B43legacy_PHY_OFDM(0x78) /* Hardware power TSSI control */
141#define B43legacy_PHY_NRSSITHRES B43legacy_PHY_OFDM(0x8A) /* NRSSI threshold */
142#define B43legacy_PHY_ANTWRSETT B43legacy_PHY_OFDM(0x8C) /* Antenna WR settle */
143#define B43legacy_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
144#define B43legacy_PHY_CLIPPWRDOWNT B43legacy_PHY_OFDM(0x93) /* Clip powerdown threshold */
145#define B43legacy_PHY_OFDM9B B43legacy_PHY_OFDM(0x9B) /* FIXME rename */
146#define B43legacy_PHY_N1P1GAIN B43legacy_PHY_OFDM(0xA0)
147#define B43legacy_PHY_P1P2GAIN B43legacy_PHY_OFDM(0xA1)
148#define B43legacy_PHY_N1N2GAIN B43legacy_PHY_OFDM(0xA2)
149#define B43legacy_PHY_CLIPTHRES B43legacy_PHY_OFDM(0xA3)
150#define B43legacy_PHY_CLIPN1P2THRES B43legacy_PHY_OFDM(0xA4)
151#define B43legacy_PHY_DIVSRCHIDX B43legacy_PHY_OFDM(0xA8) /* Divider search gain/index */
152#define B43legacy_PHY_CLIPP2THRES B43legacy_PHY_OFDM(0xA9)
153#define B43legacy_PHY_CLIPP3THRES B43legacy_PHY_OFDM(0xAA)
154#define B43legacy_PHY_DIVP1P2GAIN B43legacy_PHY_OFDM(0xAB)
155#define B43legacy_PHY_DIVSRCHGAINBACK B43legacy_PHY_OFDM(0xAD) /* Divider search gain back */
156#define B43legacy_PHY_DIVSRCHGAINCHNG B43legacy_PHY_OFDM(0xAE) /* Divider search gain change */
157#define B43legacy_PHY_CRSTHRES1_R1 B43legacy_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */
158#define B43legacy_PHY_CRSTHRES2_R1 B43legacy_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */
159#define B43legacy_PHY_TSSIP_LTBASE B43legacy_PHY_OFDM(0x380) /* TSSI power lookup table base */
160#define B43legacy_PHY_DC_LTBASE B43legacy_PHY_OFDM(0x3A0) /* DC lookup table base */
161#define B43legacy_PHY_GAIN_LTBASE B43legacy_PHY_OFDM(0x3C0) /* Gain lookup table base */
162
163void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
164
165/* Masks for the different PHY versioning registers. */
166#define B43legacy_PHYVER_ANALOG 0xF000
167#define B43legacy_PHYVER_ANALOG_SHIFT 12
168#define B43legacy_PHYVER_TYPE 0x0F00
169#define B43legacy_PHYVER_TYPE_SHIFT 8
170#define B43legacy_PHYVER_VERSION 0x00FF
171
172struct b43legacy_wldev;
173
174void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev);
175#define b43legacy_phy_lock(bcm, flags) \
176 do { \
177 local_irq_save(flags); \
178 b43legacy_raw_phy_lock(bcm); \
179 } while (0)
180void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev);
181#define b43legacy_phy_unlock(bcm, flags) \
182 do { \
183 b43legacy_raw_phy_unlock(bcm); \
184 local_irq_restore(flags); \
185 } while (0)
186
187/* Card uses the loopback gain stuff */
188#define has_loopback_gain(phy) \
189 (((phy)->rev > 1) || ((phy)->gmode))
190
191u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset);
192void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
193
194int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev);
195int b43legacy_phy_init(struct b43legacy_wldev *dev);
196
197void b43legacy_set_rx_antenna(struct b43legacy_wldev *dev, int antenna);
198
199void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev);
200void b43legacy_phy_calibrate(struct b43legacy_wldev *dev);
201int b43legacy_phy_connect(struct b43legacy_wldev *dev, int connect);
202
203void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev);
204void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev);
205void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev);
206
207/* Adjust the LocalOscillator to the saved values.
208 * "fixed" is only set to 1 once in initialization. Set to 0 otherwise.
209 */
210void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed);
211void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev);
212
213void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
214 u16 baseband_attenuation);
215
216void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
217 int bit25, int bit26);
218
219#endif /* B43legacy_PHY_H_ */
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
new file mode 100644
index 00000000000..de843ac147a
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -0,0 +1,668 @@
1/*
2
3 Broadcom B43legacy wireless driver
4
5 PIO Transmission
6
7 Copyright (c) 2005 Michael Buesch <mb@bu3sch.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 "b43legacy.h"
27#include "pio.h"
28#include "main.h"
29#include "xmit.h"
30
31#include <linux/delay.h>
32
33
34static void tx_start(struct b43legacy_pioqueue *queue)
35{
36 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
37 B43legacy_PIO_TXCTL_INIT);
38}
39
40static void tx_octet(struct b43legacy_pioqueue *queue,
41 u8 octet)
42{
43 if (queue->need_workarounds) {
44 b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
45 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
46 B43legacy_PIO_TXCTL_WRITELO);
47 } else {
48 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
49 B43legacy_PIO_TXCTL_WRITELO);
50 b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
51 }
52}
53
54static u16 tx_get_next_word(const u8 *txhdr,
55 const u8 *packet,
56 size_t txhdr_size,
57 unsigned int *pos)
58{
59 const u8 *source;
60 unsigned int i = *pos;
61 u16 ret;
62
63 if (i < txhdr_size)
64 source = txhdr;
65 else {
66 source = packet;
67 i -= txhdr_size;
68 }
69 ret = le16_to_cpu(*((__le16 *)(source + i)));
70 *pos += 2;
71
72 return ret;
73}
74
75static void tx_data(struct b43legacy_pioqueue *queue,
76 u8 *txhdr,
77 const u8 *packet,
78 unsigned int octets)
79{
80 u16 data;
81 unsigned int i = 0;
82
83 if (queue->need_workarounds) {
84 data = tx_get_next_word(txhdr, packet,
85 sizeof(struct b43legacy_txhdr_fw3), &i);
86 b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
87 }
88 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
89 B43legacy_PIO_TXCTL_WRITELO |
90 B43legacy_PIO_TXCTL_WRITEHI);
91 while (i < octets - 1) {
92 data = tx_get_next_word(txhdr, packet,
93 sizeof(struct b43legacy_txhdr_fw3), &i);
94 b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
95 }
96 if (octets % 2)
97 tx_octet(queue, packet[octets -
98 sizeof(struct b43legacy_txhdr_fw3) - 1]);
99}
100
101static void tx_complete(struct b43legacy_pioqueue *queue,
102 struct sk_buff *skb)
103{
104 if (queue->need_workarounds) {
105 b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
106 skb->data[skb->len - 1]);
107 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
108 B43legacy_PIO_TXCTL_WRITELO |
109 B43legacy_PIO_TXCTL_COMPLETE);
110 } else
111 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
112 B43legacy_PIO_TXCTL_COMPLETE);
113}
114
115static u16 generate_cookie(struct b43legacy_pioqueue *queue,
116 struct b43legacy_pio_txpacket *packet)
117{
118 u16 cookie = 0x0000;
119 int packetindex;
120
121 /* We use the upper 4 bits for the PIO
122 * controller ID and the lower 12 bits
123 * for the packet index (in the cache).
124 */
125 switch (queue->mmio_base) {
126 case B43legacy_MMIO_PIO1_BASE:
127 break;
128 case B43legacy_MMIO_PIO2_BASE:
129 cookie = 0x1000;
130 break;
131 case B43legacy_MMIO_PIO3_BASE:
132 cookie = 0x2000;
133 break;
134 case B43legacy_MMIO_PIO4_BASE:
135 cookie = 0x3000;
136 break;
137 default:
138 B43legacy_WARN_ON(1);
139 }
140 packetindex = pio_txpacket_getindex(packet);
141 B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
142 cookie |= (u16)packetindex;
143
144 return cookie;
145}
146
147static
148struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
149 u16 cookie,
150 struct b43legacy_pio_txpacket **packet)
151{
152 struct b43legacy_pio *pio = &dev->pio;
153 struct b43legacy_pioqueue *queue = NULL;
154 int packetindex;
155
156 switch (cookie & 0xF000) {
157 case 0x0000:
158 queue = pio->queue0;
159 break;
160 case 0x1000:
161 queue = pio->queue1;
162 break;
163 case 0x2000:
164 queue = pio->queue2;
165 break;
166 case 0x3000:
167 queue = pio->queue3;
168 break;
169 default:
170 B43legacy_WARN_ON(1);
171 }
172 packetindex = (cookie & 0x0FFF);
173 B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
174 < B43legacy_PIO_MAXTXPACKETS));
175 *packet = &(queue->tx_packets_cache[packetindex]);
176
177 return queue;
178}
179
180union txhdr_union {
181 struct b43legacy_txhdr_fw3 txhdr_fw3;
182};
183
184static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
185 struct sk_buff *skb,
186 struct b43legacy_pio_txpacket *packet,
187 size_t txhdr_size)
188{
189 union txhdr_union txhdr_data;
190 u8 *txhdr = NULL;
191 unsigned int octets;
192
193 txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
194
195 B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
196 b43legacy_generate_txhdr(queue->dev,
197 txhdr, skb->data, skb->len,
198 &packet->txstat.control,
199 generate_cookie(queue, packet));
200
201 tx_start(queue);
202 octets = skb->len + txhdr_size;
203 if (queue->need_workarounds)
204 octets--;
205 tx_data(queue, txhdr, (u8 *)skb->data, octets);
206 tx_complete(queue, skb);
207}
208
209static void free_txpacket(struct b43legacy_pio_txpacket *packet,
210 int irq_context)
211{
212 struct b43legacy_pioqueue *queue = packet->queue;
213
214 if (packet->skb) {
215 if (irq_context)
216 dev_kfree_skb_irq(packet->skb);
217 else
218 dev_kfree_skb(packet->skb);
219 }
220 list_move(&packet->list, &queue->txfree);
221 queue->nr_txfree++;
222}
223
224static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
225{
226 struct b43legacy_pioqueue *queue = packet->queue;
227 struct sk_buff *skb = packet->skb;
228 u16 octets;
229
230 octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
231 if (queue->tx_devq_size < octets) {
232 b43legacywarn(queue->dev->wl, "PIO queue too small. "
233 "Dropping packet.\n");
234 /* Drop it silently (return success) */
235 free_txpacket(packet, 1);
236 return 0;
237 }
238 B43legacy_WARN_ON(queue->tx_devq_packets >
239 B43legacy_PIO_MAXTXDEVQPACKETS);
240 B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
241 /* Check if there is sufficient free space on the device
242 * TX queue. If not, return and let the TX tasklet
243 * retry later.
244 */
245 if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
246 return -EBUSY;
247 if (queue->tx_devq_used + octets > queue->tx_devq_size)
248 return -EBUSY;
249 /* Now poke the device. */
250 pio_tx_write_fragment(queue, skb, packet,
251 sizeof(struct b43legacy_txhdr_fw3));
252
253 /* Account for the packet size.
254 * (We must not overflow the device TX queue)
255 */
256 queue->tx_devq_packets++;
257 queue->tx_devq_used += octets;
258
259 /* Transmission started, everything ok, move the
260 * packet to the txrunning list.
261 */
262 list_move_tail(&packet->list, &queue->txrunning);
263
264 return 0;
265}
266
267static void tx_tasklet(unsigned long d)
268{
269 struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d;
270 struct b43legacy_wldev *dev = queue->dev;
271 unsigned long flags;
272 struct b43legacy_pio_txpacket *packet, *tmp_packet;
273 int err;
274 u16 txctl;
275
276 spin_lock_irqsave(&dev->wl->irq_lock, flags);
277 if (queue->tx_frozen)
278 goto out_unlock;
279 txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
280 if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
281 goto out_unlock;
282
283 list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
284 /* Try to transmit the packet. This can fail, if
285 * the device queue is full. In case of failure, the
286 * packet is left in the txqueue.
287 * If transmission succeed, the packet is moved to txrunning.
288 * If it is impossible to transmit the packet, it
289 * is dropped.
290 */
291 err = pio_tx_packet(packet);
292 if (err)
293 break;
294 }
295out_unlock:
296 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
297}
298
299static void setup_txqueues(struct b43legacy_pioqueue *queue)
300{
301 struct b43legacy_pio_txpacket *packet;
302 int i;
303
304 queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
305 for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
306 packet = &(queue->tx_packets_cache[i]);
307
308 packet->queue = queue;
309 INIT_LIST_HEAD(&packet->list);
310
311 list_add(&packet->list, &queue->txfree);
312 }
313}
314
315static
316struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
317 u16 pio_mmio_base)
318{
319 struct b43legacy_pioqueue *queue;
320 u32 value;
321 u16 qsize;
322
323 queue = kzalloc(sizeof(*queue), GFP_KERNEL);
324 if (!queue)
325 goto out;
326
327 queue->dev = dev;
328 queue->mmio_base = pio_mmio_base;
329 queue->need_workarounds = (dev->dev->id.revision < 3);
330
331 INIT_LIST_HEAD(&queue->txfree);
332 INIT_LIST_HEAD(&queue->txqueue);
333 INIT_LIST_HEAD(&queue->txrunning);
334 tasklet_init(&queue->txtask, tx_tasklet,
335 (unsigned long)queue);
336
337 value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
338 value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
339 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
340
341 qsize = b43legacy_read16(dev, queue->mmio_base
342 + B43legacy_PIO_TXQBUFSIZE);
343 if (qsize == 0) {
344 b43legacyerr(dev->wl, "This card does not support PIO "
345 "operation mode. Please use DMA mode "
346 "(module parameter pio=0).\n");
347 goto err_freequeue;
348 }
349 if (qsize <= B43legacy_PIO_TXQADJUST) {
350 b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
351 qsize);
352 goto err_freequeue;
353 }
354 qsize -= B43legacy_PIO_TXQADJUST;
355 queue->tx_devq_size = qsize;
356
357 setup_txqueues(queue);
358
359out:
360 return queue;
361
362err_freequeue:
363 kfree(queue);
364 queue = NULL;
365 goto out;
366}
367
368static void cancel_transfers(struct b43legacy_pioqueue *queue)
369{
370 struct b43legacy_pio_txpacket *packet, *tmp_packet;
371
372 tasklet_disable(&queue->txtask);
373
374 list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
375 free_txpacket(packet, 0);
376 list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
377 free_txpacket(packet, 0);
378}
379
380static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
381{
382 if (!queue)
383 return;
384
385 cancel_transfers(queue);
386 kfree(queue);
387}
388
389void b43legacy_pio_free(struct b43legacy_wldev *dev)
390{
391 struct b43legacy_pio *pio;
392
393 if (!b43legacy_using_pio(dev))
394 return;
395 pio = &dev->pio;
396
397 b43legacy_destroy_pioqueue(pio->queue3);
398 pio->queue3 = NULL;
399 b43legacy_destroy_pioqueue(pio->queue2);
400 pio->queue2 = NULL;
401 b43legacy_destroy_pioqueue(pio->queue1);
402 pio->queue1 = NULL;
403 b43legacy_destroy_pioqueue(pio->queue0);
404 pio->queue0 = NULL;
405}
406
407int b43legacy_pio_init(struct b43legacy_wldev *dev)
408{
409 struct b43legacy_pio *pio = &dev->pio;
410 struct b43legacy_pioqueue *queue;
411 int err = -ENOMEM;
412
413 queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
414 if (!queue)
415 goto out;
416 pio->queue0 = queue;
417
418 queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
419 if (!queue)
420 goto err_destroy0;
421 pio->queue1 = queue;
422
423 queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
424 if (!queue)
425 goto err_destroy1;
426 pio->queue2 = queue;
427
428 queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
429 if (!queue)
430 goto err_destroy2;
431 pio->queue3 = queue;
432
433 if (dev->dev->id.revision < 3)
434 dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
435
436 b43legacydbg(dev->wl, "PIO initialized\n");
437 err = 0;
438out:
439 return err;
440
441err_destroy2:
442 b43legacy_destroy_pioqueue(pio->queue2);
443 pio->queue2 = NULL;
444err_destroy1:
445 b43legacy_destroy_pioqueue(pio->queue1);
446 pio->queue1 = NULL;
447err_destroy0:
448 b43legacy_destroy_pioqueue(pio->queue0);
449 pio->queue0 = NULL;
450 goto out;
451}
452
453int b43legacy_pio_tx(struct b43legacy_wldev *dev,
454 struct sk_buff *skb,
455 struct ieee80211_tx_control *ctl)
456{
457 struct b43legacy_pioqueue *queue = dev->pio.queue1;
458 struct b43legacy_pio_txpacket *packet;
459
460 B43legacy_WARN_ON(queue->tx_suspended);
461 B43legacy_WARN_ON(list_empty(&queue->txfree));
462
463 packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
464 list);
465 packet->skb = skb;
466
467 memset(&packet->txstat, 0, sizeof(packet->txstat));
468 memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
469
470 list_move_tail(&packet->list, &queue->txqueue);
471 queue->nr_txfree--;
472 queue->nr_tx_packets++;
473 B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
474
475 tasklet_schedule(&queue->txtask);
476
477 return 0;
478}
479
480void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
481 const struct b43legacy_txstatus *status)
482{
483 struct b43legacy_pioqueue *queue;
484 struct b43legacy_pio_txpacket *packet;
485
486 queue = parse_cookie(dev, status->cookie, &packet);
487 B43legacy_WARN_ON(!queue);
488
489 queue->tx_devq_packets--;
490 queue->tx_devq_used -= (packet->skb->len +
491 sizeof(struct b43legacy_txhdr_fw3));
492
493 if (status->acked)
494 packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
495 packet->txstat.retry_count = status->frame_count - 1;
496 ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
497 &(packet->txstat));
498 packet->skb = NULL;
499
500 free_txpacket(packet, 1);
501 /* If there are packets on the txqueue, poke the tasklet
502 * to transmit them.
503 */
504 if (!list_empty(&queue->txqueue))
505 tasklet_schedule(&queue->txtask);
506}
507
508void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
509 struct ieee80211_tx_queue_stats *stats)
510{
511 struct b43legacy_pio *pio = &dev->pio;
512 struct b43legacy_pioqueue *queue;
513 struct ieee80211_tx_queue_stats_data *data;
514
515 queue = pio->queue1;
516 data = &(stats->data[0]);
517 data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
518 data->limit = B43legacy_PIO_MAXTXPACKETS;
519 data->count = queue->nr_tx_packets;
520}
521
522static void pio_rx_error(struct b43legacy_pioqueue *queue,
523 int clear_buffers,
524 const char *error)
525{
526 int i;
527
528 b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
529 b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
530 B43legacy_PIO_RXCTL_READY);
531 if (clear_buffers) {
532 B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
533 for (i = 0; i < 15; i++) {
534 /* Dummy read. */
535 b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
536 }
537 }
538}
539
540void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
541{
542 __le16 preamble[21] = { 0 };
543 struct b43legacy_rxhdr_fw3 *rxhdr;
544 u16 tmp;
545 u16 len;
546 u16 macstat;
547 int i;
548 int preamble_readwords;
549 struct sk_buff *skb;
550
551 tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
552 if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
553 return;
554 b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
555 B43legacy_PIO_RXCTL_DATAAVAILABLE);
556
557 for (i = 0; i < 10; i++) {
558 tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
559 if (tmp & B43legacy_PIO_RXCTL_READY)
560 goto data_ready;
561 udelay(10);
562 }
563 b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
564 return;
565data_ready:
566
567 len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
568 if (unlikely(len > 0x700)) {
569 pio_rx_error(queue, 0, "len > 0x700");
570 return;
571 }
572 if (unlikely(len == 0 && queue->mmio_base !=
573 B43legacy_MMIO_PIO4_BASE)) {
574 pio_rx_error(queue, 0, "len == 0");
575 return;
576 }
577 preamble[0] = cpu_to_le16(len);
578 if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
579 preamble_readwords = 14 / sizeof(u16);
580 else
581 preamble_readwords = 18 / sizeof(u16);
582 for (i = 0; i < preamble_readwords; i++) {
583 tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
584 preamble[i + 1] = cpu_to_le16(tmp);
585 }
586 rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
587 macstat = le16_to_cpu(rxhdr->mac_status);
588 if (macstat & B43legacy_RX_MAC_FCSERR) {
589 pio_rx_error(queue,
590 (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
591 "Frame FCS error");
592 return;
593 }
594 if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
595 /* We received an xmit status. */
596 struct b43legacy_hwtxstatus *hw;
597
598 hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
599 b43legacy_handle_hwtxstatus(queue->dev, hw);
600
601 return;
602 }
603
604 skb = dev_alloc_skb(len);
605 if (unlikely(!skb)) {
606 pio_rx_error(queue, 1, "OOM");
607 return;
608 }
609 skb_put(skb, len);
610 for (i = 0; i < len - 1; i += 2) {
611 tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
612 *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
613 }
614 if (len % 2) {
615 tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
616 skb->data[len - 1] = (tmp & 0x00FF);
617 }
618 b43legacy_rx(queue->dev, skb, rxhdr);
619}
620
621void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
622{
623 b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
624 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
625 b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
626 | B43legacy_PIO_TXCTL_SUSPEND);
627}
628
629void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
630{
631 b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
632 b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
633 & ~B43legacy_PIO_TXCTL_SUSPEND);
634 b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
635 tasklet_schedule(&queue->txtask);
636}
637
638void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
639{
640 struct b43legacy_pio *pio;
641
642 B43legacy_WARN_ON(!b43legacy_using_pio(dev));
643 pio = &dev->pio;
644 pio->queue0->tx_frozen = 1;
645 pio->queue1->tx_frozen = 1;
646 pio->queue2->tx_frozen = 1;
647 pio->queue3->tx_frozen = 1;
648}
649
650void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
651{
652 struct b43legacy_pio *pio;
653
654 B43legacy_WARN_ON(!b43legacy_using_pio(dev));
655 pio = &dev->pio;
656 pio->queue0->tx_frozen = 0;
657 pio->queue1->tx_frozen = 0;
658 pio->queue2->tx_frozen = 0;
659 pio->queue3->tx_frozen = 0;
660 if (!list_empty(&pio->queue0->txqueue))
661 tasklet_schedule(&pio->queue0->txtask);
662 if (!list_empty(&pio->queue1->txqueue))
663 tasklet_schedule(&pio->queue1->txtask);
664 if (!list_empty(&pio->queue2->txqueue))
665 tasklet_schedule(&pio->queue2->txtask);
666 if (!list_empty(&pio->queue3->txqueue))
667 tasklet_schedule(&pio->queue3->txtask);
668}
diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h
new file mode 100644
index 00000000000..5bfed0c4003
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.h
@@ -0,0 +1,172 @@
1#ifndef B43legacy_PIO_H_
2#define B43legacy_PIO_H_
3
4#include "b43legacy.h"
5
6#include <linux/interrupt.h>
7#include <linux/list.h>
8#include <linux/skbuff.h>
9
10
11#define B43legacy_PIO_TXCTL 0x00
12#define B43legacy_PIO_TXDATA 0x02
13#define B43legacy_PIO_TXQBUFSIZE 0x04
14#define B43legacy_PIO_RXCTL 0x08
15#define B43legacy_PIO_RXDATA 0x0A
16
17#define B43legacy_PIO_TXCTL_WRITELO (1 << 0)
18#define B43legacy_PIO_TXCTL_WRITEHI (1 << 1)
19#define B43legacy_PIO_TXCTL_COMPLETE (1 << 2)
20#define B43legacy_PIO_TXCTL_INIT (1 << 3)
21#define B43legacy_PIO_TXCTL_SUSPEND (1 << 7)
22
23#define B43legacy_PIO_RXCTL_DATAAVAILABLE (1 << 0)
24#define B43legacy_PIO_RXCTL_READY (1 << 1)
25
26/* PIO constants */
27#define B43legacy_PIO_MAXTXDEVQPACKETS 31
28#define B43legacy_PIO_TXQADJUST 80
29
30/* PIO tuning knobs */
31#define B43legacy_PIO_MAXTXPACKETS 256
32
33
34
35#ifdef CONFIG_B43LEGACY_PIO
36
37
38struct b43legacy_pioqueue;
39struct b43legacy_xmitstatus;
40
41struct b43legacy_pio_txpacket {
42 struct b43legacy_pioqueue *queue;
43 struct sk_buff *skb;
44 struct ieee80211_tx_status txstat;
45 struct list_head list;
46};
47
48#define pio_txpacket_getindex(packet) ((int)((packet) - \
49 (packet)->queue->tx_packets_cache))
50
51struct b43legacy_pioqueue {
52 struct b43legacy_wldev *dev;
53 u16 mmio_base;
54
55 bool tx_suspended;
56 bool tx_frozen;
57 bool need_workarounds; /* 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 b43legacy_pio_txpacket
84 tx_packets_cache[B43legacy_PIO_MAXTXPACKETS];
85};
86
87static inline
88u16 b43legacy_pio_read(struct b43legacy_pioqueue *queue,
89 u16 offset)
90{
91 return b43legacy_read16(queue->dev, queue->mmio_base + offset);
92}
93
94static inline
95void b43legacy_pio_write(struct b43legacy_pioqueue *queue,
96 u16 offset, u16 value)
97{
98 b43legacy_write16(queue->dev, queue->mmio_base + offset, value);
99 mmiowb();
100}
101
102
103int b43legacy_pio_init(struct b43legacy_wldev *dev);
104void b43legacy_pio_free(struct b43legacy_wldev *dev);
105
106int b43legacy_pio_tx(struct b43legacy_wldev *dev,
107 struct sk_buff *skb,
108 struct ieee80211_tx_control *ctl);
109void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
110 const struct b43legacy_txstatus *status);
111void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
112 struct ieee80211_tx_queue_stats *stats);
113void b43legacy_pio_rx(struct b43legacy_pioqueue *queue);
114
115/* Suspend TX queue in hardware. */
116void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue);
117void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue);
118/* Suspend (freeze) the TX tasklet (software level). */
119void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev);
120void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev);
121
122#else /* CONFIG_B43LEGACY_PIO */
123
124static inline
125int b43legacy_pio_init(struct b43legacy_wldev *dev)
126{
127 return 0;
128}
129static inline
130void b43legacy_pio_free(struct b43legacy_wldev *dev)
131{
132}
133static inline
134int b43legacy_pio_tx(struct b43legacy_wldev *dev,
135 struct sk_buff *skb,
136 struct ieee80211_tx_control *ctl)
137{
138 return 0;
139}
140static inline
141void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
142 const struct b43legacy_txstatus *status)
143{
144}
145static inline
146void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
147 struct ieee80211_tx_queue_stats *stats)
148{
149}
150static inline
151void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
152{
153}
154static inline
155void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
156{
157}
158static inline
159void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
160{
161}
162static inline
163void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
164{
165}
166static inline
167void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
168{
169}
170
171#endif /* CONFIG_B43LEGACY_PIO */
172#endif /* B43legacy_PIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
new file mode 100644
index 00000000000..2a11ee63f40
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -0,0 +1,2131 @@
1/*
2
3 Broadcom B43legacy 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 Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
11
12 Some parts of the code in this file are derived from the ipw2200
13 driver Copyright(c) 2003 - 2004 Intel Corporation.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
28 Boston, MA 02110-1301, USA.
29
30*/
31
32#include <linux/delay.h>
33
34#include "b43legacy.h"
35#include "main.h"
36#include "phy.h"
37#include "radio.h"
38#include "ilt.h"
39
40
41/* Table for b43legacy_radio_calibrationvalue() */
42static const u16 rcc_table[16] = {
43 0x0002, 0x0003, 0x0001, 0x000F,
44 0x0006, 0x0007, 0x0005, 0x000F,
45 0x000A, 0x000B, 0x0009, 0x000F,
46 0x000E, 0x000F, 0x000D, 0x000F,
47};
48
49/* Reverse the bits of a 4bit value.
50 * Example: 1101 is flipped 1011
51 */
52static u16 flip_4bit(u16 value)
53{
54 u16 flipped = 0x0000;
55
56 B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));
57
58 flipped |= (value & 0x0001) << 3;
59 flipped |= (value & 0x0002) << 1;
60 flipped |= (value & 0x0004) >> 1;
61 flipped |= (value & 0x0008) >> 3;
62
63 return flipped;
64}
65
66/* Get the freq, as it has to be written to the device. */
67static inline
68u16 channel2freq_bg(u8 channel)
69{
70 /* Frequencies are given as frequencies_bg[index] + 2.4GHz
71 * Starting with channel 1
72 */
73 static const u16 frequencies_bg[14] = {
74 12, 17, 22, 27,
75 32, 37, 42, 47,
76 52, 57, 62, 67,
77 72, 84,
78 };
79
80 if (unlikely(channel < 1 || channel > 14)) {
81 printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
82 channel);
83 dump_stack();
84 return 2412;
85 }
86
87 return frequencies_bg[channel - 1];
88}
89
90void b43legacy_radio_lock(struct b43legacy_wldev *dev)
91{
92 u32 status;
93
94 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
95 status |= B43legacy_SBF_RADIOREG_LOCK;
96 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
97 mmiowb();
98 udelay(10);
99}
100
101void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
102{
103 u32 status;
104
105 b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
106 status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
107 status &= ~B43legacy_SBF_RADIOREG_LOCK;
108 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
109 mmiowb();
110}
111
112u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
113{
114 struct b43legacy_phy *phy = &dev->phy;
115
116 switch (phy->type) {
117 case B43legacy_PHYTYPE_B:
118 if (phy->radio_ver == 0x2053) {
119 if (offset < 0x70)
120 offset += 0x80;
121 else if (offset < 0x80)
122 offset += 0x70;
123 } else if (phy->radio_ver == 0x2050)
124 offset |= 0x80;
125 else
126 B43legacy_WARN_ON(1);
127 break;
128 case B43legacy_PHYTYPE_G:
129 offset |= 0x80;
130 break;
131 default:
132 B43legacy_BUG_ON(1);
133 }
134
135 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
136 return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
137}
138
139void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
140{
141 b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
142 mmiowb();
143 b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
144}
145
146static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
147 s16 first, s16 second, s16 third)
148{
149 struct b43legacy_phy *phy = &dev->phy;
150 u16 i;
151 u16 start = 0x08;
152 u16 end = 0x18;
153 u16 offset = 0x0400;
154 u16 tmp;
155
156 if (phy->rev <= 1) {
157 offset = 0x5000;
158 start = 0x10;
159 end = 0x20;
160 }
161
162 for (i = 0; i < 4; i++)
163 b43legacy_ilt_write(dev, offset + i, first);
164
165 for (i = start; i < end; i++)
166 b43legacy_ilt_write(dev, offset + i, second);
167
168 if (third != -1) {
169 tmp = ((u16)third << 14) | ((u16)third << 6);
170 b43legacy_phy_write(dev, 0x04A0,
171 (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
172 | tmp);
173 b43legacy_phy_write(dev, 0x04A1,
174 (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
175 | tmp);
176 b43legacy_phy_write(dev, 0x04A2,
177 (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
178 | tmp);
179 }
180 b43legacy_dummy_transmission(dev);
181}
182
183static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
184{
185 struct b43legacy_phy *phy = &dev->phy;
186 u16 i;
187 u16 tmp;
188 u16 offset = 0x0400;
189 u16 start = 0x0008;
190 u16 end = 0x0018;
191
192 if (phy->rev <= 1) {
193 offset = 0x5000;
194 start = 0x0010;
195 end = 0x0020;
196 }
197
198 for (i = 0; i < 4; i++) {
199 tmp = (i & 0xFFFC);
200 tmp |= (i & 0x0001) << 1;
201 tmp |= (i & 0x0002) >> 1;
202
203 b43legacy_ilt_write(dev, offset + i, tmp);
204 }
205
206 for (i = start; i < end; i++)
207 b43legacy_ilt_write(dev, offset + i, i - start);
208
209 b43legacy_phy_write(dev, 0x04A0,
210 (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
211 | 0x4040);
212 b43legacy_phy_write(dev, 0x04A1,
213 (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
214 | 0x4040);
215 b43legacy_phy_write(dev, 0x04A2,
216 (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
217 | 0x4000);
218 b43legacy_dummy_transmission(dev);
219}
220
221/* Synthetic PU workaround */
222static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
223 u8 channel)
224{
225 struct b43legacy_phy *phy = &dev->phy;
226
227 might_sleep();
228
229 if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
230 /* We do not need the workaround. */
231 return;
232
233 if (channel <= 10)
234 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
235 channel2freq_bg(channel + 4));
236 else
237 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
238 channel2freq_bg(channel));
239 msleep(1);
240 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
241 channel2freq_bg(channel));
242}
243
244u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
245{
246 struct b43legacy_phy *phy = &dev->phy;
247 u8 ret = 0;
248 u16 saved;
249 u16 rssi;
250 u16 temp;
251 int i;
252 int j = 0;
253
254 saved = b43legacy_phy_read(dev, 0x0403);
255 b43legacy_radio_selectchannel(dev, channel, 0);
256 b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
257 if (phy->aci_hw_rssi)
258 rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
259 else
260 rssi = saved & 0x3F;
261 /* clamp temp to signed 5bit */
262 if (rssi > 32)
263 rssi -= 64;
264 for (i = 0; i < 100; i++) {
265 temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
266 if (temp > 32)
267 temp -= 64;
268 if (temp < rssi)
269 j++;
270 if (j >= 20)
271 ret = 1;
272 }
273 b43legacy_phy_write(dev, 0x0403, saved);
274
275 return ret;
276}
277
278u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
279{
280 struct b43legacy_phy *phy = &dev->phy;
281 u8 ret[13];
282 unsigned int channel = phy->channel;
283 unsigned int i;
284 unsigned int j;
285 unsigned int start;
286 unsigned int end;
287 unsigned long phylock_flags;
288
289 if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
290 return 0;
291
292 b43legacy_phy_lock(dev, phylock_flags);
293 b43legacy_radio_lock(dev);
294 b43legacy_phy_write(dev, 0x0802,
295 b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
296 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
297 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
298 & 0x7FFF);
299 b43legacy_set_all_gains(dev, 3, 8, 1);
300
301 start = (channel - 5 > 0) ? channel - 5 : 1;
302 end = (channel + 5 < 14) ? channel + 5 : 13;
303
304 for (i = start; i <= end; i++) {
305 if (abs(channel - i) > 2)
306 ret[i-1] = b43legacy_radio_aci_detect(dev, i);
307 }
308 b43legacy_radio_selectchannel(dev, channel, 0);
309 b43legacy_phy_write(dev, 0x0802,
310 (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
311 | 0x0003);
312 b43legacy_phy_write(dev, 0x0403,
313 b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
314 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
315 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
316 | 0x8000);
317 b43legacy_set_original_gains(dev);
318 for (i = 0; i < 13; i++) {
319 if (!ret[i])
320 continue;
321 end = (i + 5 < 13) ? i + 5 : 13;
322 for (j = i; j < end; j++)
323 ret[j] = 1;
324 }
325 b43legacy_radio_unlock(dev);
326 b43legacy_phy_unlock(dev, phylock_flags);
327
328 return ret[channel - 1];
329}
330
331/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
332void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
333{
334 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
335 mmiowb();
336 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
337}
338
339/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
340s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
341{
342 u16 val;
343
344 b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
345 val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
346
347 return (s16)val;
348}
349
350/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
351void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
352{
353 u16 i;
354 s16 tmp;
355
356 for (i = 0; i < 64; i++) {
357 tmp = b43legacy_nrssi_hw_read(dev, i);
358 tmp -= val;
359 tmp = limit_value(tmp, -32, 31);
360 b43legacy_nrssi_hw_write(dev, i, tmp);
361 }
362}
363
364/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
365void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
366{
367 struct b43legacy_phy *phy = &dev->phy;
368 s16 i;
369 s16 delta;
370 s32 tmp;
371
372 delta = 0x1F - phy->nrssi[0];
373 for (i = 0; i < 64; i++) {
374 tmp = (i - delta) * phy->nrssislope;
375 tmp /= 0x10000;
376 tmp += 0x3A;
377 tmp = limit_value(tmp, 0, 0x3F);
378 phy->nrssi_lt[i] = tmp;
379 }
380}
381
382static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
383{
384 struct b43legacy_phy *phy = &dev->phy;
385 u16 backup[20] = { 0 };
386 s16 v47F;
387 u16 i;
388 u16 saved = 0xFFFF;
389
390 backup[0] = b43legacy_phy_read(dev, 0x0001);
391 backup[1] = b43legacy_phy_read(dev, 0x0811);
392 backup[2] = b43legacy_phy_read(dev, 0x0812);
393 backup[3] = b43legacy_phy_read(dev, 0x0814);
394 backup[4] = b43legacy_phy_read(dev, 0x0815);
395 backup[5] = b43legacy_phy_read(dev, 0x005A);
396 backup[6] = b43legacy_phy_read(dev, 0x0059);
397 backup[7] = b43legacy_phy_read(dev, 0x0058);
398 backup[8] = b43legacy_phy_read(dev, 0x000A);
399 backup[9] = b43legacy_phy_read(dev, 0x0003);
400 backup[10] = b43legacy_radio_read16(dev, 0x007A);
401 backup[11] = b43legacy_radio_read16(dev, 0x0043);
402
403 b43legacy_phy_write(dev, 0x0429,
404 b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
405 b43legacy_phy_write(dev, 0x0001,
406 (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
407 | 0x4000);
408 b43legacy_phy_write(dev, 0x0811,
409 b43legacy_phy_read(dev, 0x0811) | 0x000C);
410 b43legacy_phy_write(dev, 0x0812,
411 (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
412 | 0x0004);
413 b43legacy_phy_write(dev, 0x0802,
414 b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
415 if (phy->rev >= 6) {
416 backup[12] = b43legacy_phy_read(dev, 0x002E);
417 backup[13] = b43legacy_phy_read(dev, 0x002F);
418 backup[14] = b43legacy_phy_read(dev, 0x080F);
419 backup[15] = b43legacy_phy_read(dev, 0x0810);
420 backup[16] = b43legacy_phy_read(dev, 0x0801);
421 backup[17] = b43legacy_phy_read(dev, 0x0060);
422 backup[18] = b43legacy_phy_read(dev, 0x0014);
423 backup[19] = b43legacy_phy_read(dev, 0x0478);
424
425 b43legacy_phy_write(dev, 0x002E, 0);
426 b43legacy_phy_write(dev, 0x002F, 0);
427 b43legacy_phy_write(dev, 0x080F, 0);
428 b43legacy_phy_write(dev, 0x0810, 0);
429 b43legacy_phy_write(dev, 0x0478,
430 b43legacy_phy_read(dev, 0x0478) | 0x0100);
431 b43legacy_phy_write(dev, 0x0801,
432 b43legacy_phy_read(dev, 0x0801) | 0x0040);
433 b43legacy_phy_write(dev, 0x0060,
434 b43legacy_phy_read(dev, 0x0060) | 0x0040);
435 b43legacy_phy_write(dev, 0x0014,
436 b43legacy_phy_read(dev, 0x0014) | 0x0200);
437 }
438 b43legacy_radio_write16(dev, 0x007A,
439 b43legacy_radio_read16(dev, 0x007A) | 0x0070);
440 b43legacy_radio_write16(dev, 0x007A,
441 b43legacy_radio_read16(dev, 0x007A) | 0x0080);
442 udelay(30);
443
444 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
445 if (v47F >= 0x20)
446 v47F -= 0x40;
447 if (v47F == 31) {
448 for (i = 7; i >= 4; i--) {
449 b43legacy_radio_write16(dev, 0x007B, i);
450 udelay(20);
451 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
452 & 0x003F);
453 if (v47F >= 0x20)
454 v47F -= 0x40;
455 if (v47F < 31 && saved == 0xFFFF)
456 saved = i;
457 }
458 if (saved == 0xFFFF)
459 saved = 4;
460 } else {
461 b43legacy_radio_write16(dev, 0x007A,
462 b43legacy_radio_read16(dev, 0x007A)
463 & 0x007F);
464 b43legacy_phy_write(dev, 0x0814,
465 b43legacy_phy_read(dev, 0x0814) | 0x0001);
466 b43legacy_phy_write(dev, 0x0815,
467 b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
468 b43legacy_phy_write(dev, 0x0811,
469 b43legacy_phy_read(dev, 0x0811) | 0x000C);
470 b43legacy_phy_write(dev, 0x0812,
471 b43legacy_phy_read(dev, 0x0812) | 0x000C);
472 b43legacy_phy_write(dev, 0x0811,
473 b43legacy_phy_read(dev, 0x0811) | 0x0030);
474 b43legacy_phy_write(dev, 0x0812,
475 b43legacy_phy_read(dev, 0x0812) | 0x0030);
476 b43legacy_phy_write(dev, 0x005A, 0x0480);
477 b43legacy_phy_write(dev, 0x0059, 0x0810);
478 b43legacy_phy_write(dev, 0x0058, 0x000D);
479 if (phy->analog == 0)
480 b43legacy_phy_write(dev, 0x0003, 0x0122);
481 else
482 b43legacy_phy_write(dev, 0x000A,
483 b43legacy_phy_read(dev, 0x000A)
484 | 0x2000);
485 b43legacy_phy_write(dev, 0x0814,
486 b43legacy_phy_read(dev, 0x0814) | 0x0004);
487 b43legacy_phy_write(dev, 0x0815,
488 b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
489 b43legacy_phy_write(dev, 0x0003,
490 (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
491 | 0x0040);
492 b43legacy_radio_write16(dev, 0x007A,
493 b43legacy_radio_read16(dev, 0x007A)
494 | 0x000F);
495 b43legacy_set_all_gains(dev, 3, 0, 1);
496 b43legacy_radio_write16(dev, 0x0043,
497 (b43legacy_radio_read16(dev, 0x0043)
498 & 0x00F0) | 0x000F);
499 udelay(30);
500 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
501 if (v47F >= 0x20)
502 v47F -= 0x40;
503 if (v47F == -32) {
504 for (i = 0; i < 4; i++) {
505 b43legacy_radio_write16(dev, 0x007B, i);
506 udelay(20);
507 v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
508 8) & 0x003F);
509 if (v47F >= 0x20)
510 v47F -= 0x40;
511 if (v47F > -31 && saved == 0xFFFF)
512 saved = i;
513 }
514 if (saved == 0xFFFF)
515 saved = 3;
516 } else
517 saved = 0;
518 }
519 b43legacy_radio_write16(dev, 0x007B, saved);
520
521 if (phy->rev >= 6) {
522 b43legacy_phy_write(dev, 0x002E, backup[12]);
523 b43legacy_phy_write(dev, 0x002F, backup[13]);
524 b43legacy_phy_write(dev, 0x080F, backup[14]);
525 b43legacy_phy_write(dev, 0x0810, backup[15]);
526 }
527 b43legacy_phy_write(dev, 0x0814, backup[3]);
528 b43legacy_phy_write(dev, 0x0815, backup[4]);
529 b43legacy_phy_write(dev, 0x005A, backup[5]);
530 b43legacy_phy_write(dev, 0x0059, backup[6]);
531 b43legacy_phy_write(dev, 0x0058, backup[7]);
532 b43legacy_phy_write(dev, 0x000A, backup[8]);
533 b43legacy_phy_write(dev, 0x0003, backup[9]);
534 b43legacy_radio_write16(dev, 0x0043, backup[11]);
535 b43legacy_radio_write16(dev, 0x007A, backup[10]);
536 b43legacy_phy_write(dev, 0x0802,
537 b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
538 b43legacy_phy_write(dev, 0x0429,
539 b43legacy_phy_read(dev, 0x0429) | 0x8000);
540 b43legacy_set_original_gains(dev);
541 if (phy->rev >= 6) {
542 b43legacy_phy_write(dev, 0x0801, backup[16]);
543 b43legacy_phy_write(dev, 0x0060, backup[17]);
544 b43legacy_phy_write(dev, 0x0014, backup[18]);
545 b43legacy_phy_write(dev, 0x0478, backup[19]);
546 }
547 b43legacy_phy_write(dev, 0x0001, backup[0]);
548 b43legacy_phy_write(dev, 0x0812, backup[2]);
549 b43legacy_phy_write(dev, 0x0811, backup[1]);
550}
551
552void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
553{
554 struct b43legacy_phy *phy = &dev->phy;
555 u16 backup[18] = { 0 };
556 u16 tmp;
557 s16 nrssi0;
558 s16 nrssi1;
559
560 switch (phy->type) {
561 case B43legacy_PHYTYPE_B:
562 backup[0] = b43legacy_radio_read16(dev, 0x007A);
563 backup[1] = b43legacy_radio_read16(dev, 0x0052);
564 backup[2] = b43legacy_radio_read16(dev, 0x0043);
565 backup[3] = b43legacy_phy_read(dev, 0x0030);
566 backup[4] = b43legacy_phy_read(dev, 0x0026);
567 backup[5] = b43legacy_phy_read(dev, 0x0015);
568 backup[6] = b43legacy_phy_read(dev, 0x002A);
569 backup[7] = b43legacy_phy_read(dev, 0x0020);
570 backup[8] = b43legacy_phy_read(dev, 0x005A);
571 backup[9] = b43legacy_phy_read(dev, 0x0059);
572 backup[10] = b43legacy_phy_read(dev, 0x0058);
573 backup[11] = b43legacy_read16(dev, 0x03E2);
574 backup[12] = b43legacy_read16(dev, 0x03E6);
575 backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
576
577 tmp = b43legacy_radio_read16(dev, 0x007A);
578 tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
579 b43legacy_radio_write16(dev, 0x007A, tmp);
580 b43legacy_phy_write(dev, 0x0030, 0x00FF);
581 b43legacy_write16(dev, 0x03EC, 0x7F7F);
582 b43legacy_phy_write(dev, 0x0026, 0x0000);
583 b43legacy_phy_write(dev, 0x0015,
584 b43legacy_phy_read(dev, 0x0015) | 0x0020);
585 b43legacy_phy_write(dev, 0x002A, 0x08A3);
586 b43legacy_radio_write16(dev, 0x007A,
587 b43legacy_radio_read16(dev, 0x007A)
588 | 0x0080);
589
590 nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
591 b43legacy_radio_write16(dev, 0x007A,
592 b43legacy_radio_read16(dev, 0x007A)
593 & 0x007F);
594 if (phy->analog >= 2)
595 b43legacy_write16(dev, 0x03E6, 0x0040);
596 else if (phy->analog == 0)
597 b43legacy_write16(dev, 0x03E6, 0x0122);
598 else
599 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
600 b43legacy_read16(dev,
601 B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
602 b43legacy_phy_write(dev, 0x0020, 0x3F3F);
603 b43legacy_phy_write(dev, 0x0015, 0xF330);
604 b43legacy_radio_write16(dev, 0x005A, 0x0060);
605 b43legacy_radio_write16(dev, 0x0043,
606 b43legacy_radio_read16(dev, 0x0043)
607 & 0x00F0);
608 b43legacy_phy_write(dev, 0x005A, 0x0480);
609 b43legacy_phy_write(dev, 0x0059, 0x0810);
610 b43legacy_phy_write(dev, 0x0058, 0x000D);
611 udelay(20);
612
613 nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
614 b43legacy_phy_write(dev, 0x0030, backup[3]);
615 b43legacy_radio_write16(dev, 0x007A, backup[0]);
616 b43legacy_write16(dev, 0x03E2, backup[11]);
617 b43legacy_phy_write(dev, 0x0026, backup[4]);
618 b43legacy_phy_write(dev, 0x0015, backup[5]);
619 b43legacy_phy_write(dev, 0x002A, backup[6]);
620 b43legacy_synth_pu_workaround(dev, phy->channel);
621 if (phy->analog != 0)
622 b43legacy_write16(dev, 0x03F4, backup[13]);
623
624 b43legacy_phy_write(dev, 0x0020, backup[7]);
625 b43legacy_phy_write(dev, 0x005A, backup[8]);
626 b43legacy_phy_write(dev, 0x0059, backup[9]);
627 b43legacy_phy_write(dev, 0x0058, backup[10]);
628 b43legacy_radio_write16(dev, 0x0052, backup[1]);
629 b43legacy_radio_write16(dev, 0x0043, backup[2]);
630
631 if (nrssi0 == nrssi1)
632 phy->nrssislope = 0x00010000;
633 else
634 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
635
636 if (nrssi0 <= -4) {
637 phy->nrssi[0] = nrssi0;
638 phy->nrssi[1] = nrssi1;
639 }
640 break;
641 case B43legacy_PHYTYPE_G:
642 if (phy->radio_rev >= 9)
643 return;
644 if (phy->radio_rev == 8)
645 b43legacy_calc_nrssi_offset(dev);
646
647 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
648 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
649 & 0x7FFF);
650 b43legacy_phy_write(dev, 0x0802,
651 b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
652 backup[7] = b43legacy_read16(dev, 0x03E2);
653 b43legacy_write16(dev, 0x03E2,
654 b43legacy_read16(dev, 0x03E2) | 0x8000);
655 backup[0] = b43legacy_radio_read16(dev, 0x007A);
656 backup[1] = b43legacy_radio_read16(dev, 0x0052);
657 backup[2] = b43legacy_radio_read16(dev, 0x0043);
658 backup[3] = b43legacy_phy_read(dev, 0x0015);
659 backup[4] = b43legacy_phy_read(dev, 0x005A);
660 backup[5] = b43legacy_phy_read(dev, 0x0059);
661 backup[6] = b43legacy_phy_read(dev, 0x0058);
662 backup[8] = b43legacy_read16(dev, 0x03E6);
663 backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
664 if (phy->rev >= 3) {
665 backup[10] = b43legacy_phy_read(dev, 0x002E);
666 backup[11] = b43legacy_phy_read(dev, 0x002F);
667 backup[12] = b43legacy_phy_read(dev, 0x080F);
668 backup[13] = b43legacy_phy_read(dev,
669 B43legacy_PHY_G_LO_CONTROL);
670 backup[14] = b43legacy_phy_read(dev, 0x0801);
671 backup[15] = b43legacy_phy_read(dev, 0x0060);
672 backup[16] = b43legacy_phy_read(dev, 0x0014);
673 backup[17] = b43legacy_phy_read(dev, 0x0478);
674 b43legacy_phy_write(dev, 0x002E, 0);
675 b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
676 switch (phy->rev) {
677 case 4: case 6: case 7:
678 b43legacy_phy_write(dev, 0x0478,
679 b43legacy_phy_read(dev,
680 0x0478) | 0x0100);
681 b43legacy_phy_write(dev, 0x0801,
682 b43legacy_phy_read(dev,
683 0x0801) | 0x0040);
684 break;
685 case 3: case 5:
686 b43legacy_phy_write(dev, 0x0801,
687 b43legacy_phy_read(dev,
688 0x0801) & 0xFFBF);
689 break;
690 }
691 b43legacy_phy_write(dev, 0x0060,
692 b43legacy_phy_read(dev, 0x0060)
693 | 0x0040);
694 b43legacy_phy_write(dev, 0x0014,
695 b43legacy_phy_read(dev, 0x0014)
696 | 0x0200);
697 }
698 b43legacy_radio_write16(dev, 0x007A,
699 b43legacy_radio_read16(dev, 0x007A)
700 | 0x0070);
701 b43legacy_set_all_gains(dev, 0, 8, 0);
702 b43legacy_radio_write16(dev, 0x007A,
703 b43legacy_radio_read16(dev, 0x007A)
704 & 0x00F7);
705 if (phy->rev >= 2) {
706 b43legacy_phy_write(dev, 0x0811,
707 (b43legacy_phy_read(dev, 0x0811)
708 & 0xFFCF) | 0x0030);
709 b43legacy_phy_write(dev, 0x0812,
710 (b43legacy_phy_read(dev, 0x0812)
711 & 0xFFCF) | 0x0010);
712 }
713 b43legacy_radio_write16(dev, 0x007A,
714 b43legacy_radio_read16(dev, 0x007A)
715 | 0x0080);
716 udelay(20);
717
718 nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
719 if (nrssi0 >= 0x0020)
720 nrssi0 -= 0x0040;
721
722 b43legacy_radio_write16(dev, 0x007A,
723 b43legacy_radio_read16(dev, 0x007A)
724 & 0x007F);
725 if (phy->analog >= 2)
726 b43legacy_phy_write(dev, 0x0003,
727 (b43legacy_phy_read(dev, 0x0003)
728 & 0xFF9F) | 0x0040);
729
730 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
731 b43legacy_read16(dev,
732 B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
733 b43legacy_radio_write16(dev, 0x007A,
734 b43legacy_radio_read16(dev, 0x007A)
735 | 0x000F);
736 b43legacy_phy_write(dev, 0x0015, 0xF330);
737 if (phy->rev >= 2) {
738 b43legacy_phy_write(dev, 0x0812,
739 (b43legacy_phy_read(dev, 0x0812)
740 & 0xFFCF) | 0x0020);
741 b43legacy_phy_write(dev, 0x0811,
742 (b43legacy_phy_read(dev, 0x0811)
743 & 0xFFCF) | 0x0020);
744 }
745
746 b43legacy_set_all_gains(dev, 3, 0, 1);
747 if (phy->radio_rev == 8)
748 b43legacy_radio_write16(dev, 0x0043, 0x001F);
749 else {
750 tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
751 b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
752 tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
753 b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
754 }
755 b43legacy_phy_write(dev, 0x005A, 0x0480);
756 b43legacy_phy_write(dev, 0x0059, 0x0810);
757 b43legacy_phy_write(dev, 0x0058, 0x000D);
758 udelay(20);
759 nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
760 if (nrssi1 >= 0x0020)
761 nrssi1 -= 0x0040;
762 if (nrssi0 == nrssi1)
763 phy->nrssislope = 0x00010000;
764 else
765 phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
766 if (nrssi0 >= -4) {
767 phy->nrssi[0] = nrssi1;
768 phy->nrssi[1] = nrssi0;
769 }
770 if (phy->rev >= 3) {
771 b43legacy_phy_write(dev, 0x002E, backup[10]);
772 b43legacy_phy_write(dev, 0x002F, backup[11]);
773 b43legacy_phy_write(dev, 0x080F, backup[12]);
774 b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
775 backup[13]);
776 }
777 if (phy->rev >= 2) {
778 b43legacy_phy_write(dev, 0x0812,
779 b43legacy_phy_read(dev, 0x0812)
780 & 0xFFCF);
781 b43legacy_phy_write(dev, 0x0811,
782 b43legacy_phy_read(dev, 0x0811)
783 & 0xFFCF);
784 }
785
786 b43legacy_radio_write16(dev, 0x007A, backup[0]);
787 b43legacy_radio_write16(dev, 0x0052, backup[1]);
788 b43legacy_radio_write16(dev, 0x0043, backup[2]);
789 b43legacy_write16(dev, 0x03E2, backup[7]);
790 b43legacy_write16(dev, 0x03E6, backup[8]);
791 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
792 b43legacy_phy_write(dev, 0x0015, backup[3]);
793 b43legacy_phy_write(dev, 0x005A, backup[4]);
794 b43legacy_phy_write(dev, 0x0059, backup[5]);
795 b43legacy_phy_write(dev, 0x0058, backup[6]);
796 b43legacy_synth_pu_workaround(dev, phy->channel);
797 b43legacy_phy_write(dev, 0x0802,
798 b43legacy_phy_read(dev, 0x0802) | 0x0003);
799 b43legacy_set_original_gains(dev);
800 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
801 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
802 | 0x8000);
803 if (phy->rev >= 3) {
804 b43legacy_phy_write(dev, 0x0801, backup[14]);
805 b43legacy_phy_write(dev, 0x0060, backup[15]);
806 b43legacy_phy_write(dev, 0x0014, backup[16]);
807 b43legacy_phy_write(dev, 0x0478, backup[17]);
808 }
809 b43legacy_nrssi_mem_update(dev);
810 b43legacy_calc_nrssi_threshold(dev);
811 break;
812 default:
813 B43legacy_BUG_ON(1);
814 }
815}
816
817void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
818{
819 struct b43legacy_phy *phy = &dev->phy;
820 s32 threshold;
821 s32 a;
822 s32 b;
823 s16 tmp16;
824 u16 tmp_u16;
825
826 switch (phy->type) {
827 case B43legacy_PHYTYPE_B: {
828 if (phy->radio_ver != 0x2050)
829 return;
830 if (!(dev->dev->bus->sprom.r1.boardflags_lo &
831 B43legacy_BFL_RSSI))
832 return;
833
834 if (phy->radio_rev >= 6) {
835 threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
836 threshold += 20 * (phy->nrssi[0] + 1);
837 threshold /= 40;
838 } else
839 threshold = phy->nrssi[1] - 5;
840
841 threshold = limit_value(threshold, 0, 0x3E);
842 b43legacy_phy_read(dev, 0x0020); /* dummy read */
843 b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
844 | 0x001C);
845
846 if (phy->radio_rev >= 6) {
847 b43legacy_phy_write(dev, 0x0087, 0x0E0D);
848 b43legacy_phy_write(dev, 0x0086, 0x0C0B);
849 b43legacy_phy_write(dev, 0x0085, 0x0A09);
850 b43legacy_phy_write(dev, 0x0084, 0x0808);
851 b43legacy_phy_write(dev, 0x0083, 0x0808);
852 b43legacy_phy_write(dev, 0x0082, 0x0604);
853 b43legacy_phy_write(dev, 0x0081, 0x0302);
854 b43legacy_phy_write(dev, 0x0080, 0x0100);
855 }
856 break;
857 }
858 case B43legacy_PHYTYPE_G:
859 if (!phy->gmode ||
860 !(dev->dev->bus->sprom.r1.boardflags_lo &
861 B43legacy_BFL_RSSI)) {
862 tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
863 if (tmp16 >= 0x20)
864 tmp16 -= 0x40;
865 if (tmp16 < 3)
866 b43legacy_phy_write(dev, 0x048A,
867 (b43legacy_phy_read(dev,
868 0x048A) & 0xF000) | 0x09EB);
869 else
870 b43legacy_phy_write(dev, 0x048A,
871 (b43legacy_phy_read(dev,
872 0x048A) & 0xF000) | 0x0AED);
873 } else {
874 if (phy->interfmode ==
875 B43legacy_RADIO_INTERFMODE_NONWLAN) {
876 a = 0xE;
877 b = 0xA;
878 } else if (!phy->aci_wlan_automatic &&
879 phy->aci_enable) {
880 a = 0x13;
881 b = 0x12;
882 } else {
883 a = 0xE;
884 b = 0x11;
885 }
886
887 a = a * (phy->nrssi[1] - phy->nrssi[0]);
888 a += (phy->nrssi[0] << 6);
889 if (a < 32)
890 a += 31;
891 else
892 a += 32;
893 a = a >> 6;
894 a = limit_value(a, -31, 31);
895
896 b = b * (phy->nrssi[1] - phy->nrssi[0]);
897 b += (phy->nrssi[0] << 6);
898 if (b < 32)
899 b += 31;
900 else
901 b += 32;
902 b = b >> 6;
903 b = limit_value(b, -31, 31);
904
905 tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
906 tmp_u16 |= ((u32)b & 0x0000003F);
907 tmp_u16 |= (((u32)a & 0x0000003F) << 6);
908 b43legacy_phy_write(dev, 0x048A, tmp_u16);
909 }
910 break;
911 default:
912 B43legacy_BUG_ON(1);
913 }
914}
915
916/* Stack implementation to save/restore values from the
917 * interference mitigation code.
918 * It is save to restore values in random order.
919 */
920static void _stack_save(u32 *_stackptr, size_t *stackidx,
921 u8 id, u16 offset, u16 value)
922{
923 u32 *stackptr = &(_stackptr[*stackidx]);
924
925 B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
926 B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
927 *stackptr = offset;
928 *stackptr |= ((u32)id) << 13;
929 *stackptr |= ((u32)value) << 16;
930 (*stackidx)++;
931 B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
932}
933
934static u16 _stack_restore(u32 *stackptr,
935 u8 id, u16 offset)
936{
937 size_t i;
938
939 B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
940 B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
941 for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
942 if ((*stackptr & 0x00001FFF) != offset)
943 continue;
944 if (((*stackptr & 0x00007000) >> 13) != id)
945 continue;
946 return ((*stackptr & 0xFFFF0000) >> 16);
947 }
948 B43legacy_BUG_ON(1);
949
950 return 0;
951}
952
953#define phy_stacksave(offset) \
954 do { \
955 _stack_save(stack, &stackidx, 0x1, (offset), \
956 b43legacy_phy_read(dev, (offset))); \
957 } while (0)
958#define phy_stackrestore(offset) \
959 do { \
960 b43legacy_phy_write(dev, (offset), \
961 _stack_restore(stack, 0x1, \
962 (offset))); \
963 } while (0)
964#define radio_stacksave(offset) \
965 do { \
966 _stack_save(stack, &stackidx, 0x2, (offset), \
967 b43legacy_radio_read16(dev, (offset))); \
968 } while (0)
969#define radio_stackrestore(offset) \
970 do { \
971 b43legacy_radio_write16(dev, (offset), \
972 _stack_restore(stack, 0x2, \
973 (offset))); \
974 } while (0)
975#define ilt_stacksave(offset) \
976 do { \
977 _stack_save(stack, &stackidx, 0x3, (offset), \
978 b43legacy_ilt_read(dev, (offset))); \
979 } while (0)
980#define ilt_stackrestore(offset) \
981 do { \
982 b43legacy_ilt_write(dev, (offset), \
983 _stack_restore(stack, 0x3, \
984 (offset))); \
985 } while (0)
986
987static void
988b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
989 int mode)
990{
991 struct b43legacy_phy *phy = &dev->phy;
992 u16 tmp;
993 u16 flipped;
994 u32 tmp32;
995 size_t stackidx = 0;
996 u32 *stack = phy->interfstack;
997
998 switch (mode) {
999 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1000 if (phy->rev != 1) {
1001 b43legacy_phy_write(dev, 0x042B,
1002 b43legacy_phy_read(dev, 0x042B)
1003 | 0x0800);
1004 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1005 b43legacy_phy_read(dev,
1006 B43legacy_PHY_G_CRS) & ~0x4000);
1007 break;
1008 }
1009 radio_stacksave(0x0078);
1010 tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
1011 flipped = flip_4bit(tmp);
1012 if (flipped < 10 && flipped >= 8)
1013 flipped = 7;
1014 else if (flipped >= 10)
1015 flipped -= 3;
1016 flipped = flip_4bit(flipped);
1017 flipped = (flipped << 1) | 0x0020;
1018 b43legacy_radio_write16(dev, 0x0078, flipped);
1019
1020 b43legacy_calc_nrssi_threshold(dev);
1021
1022 phy_stacksave(0x0406);
1023 b43legacy_phy_write(dev, 0x0406, 0x7E28);
1024
1025 b43legacy_phy_write(dev, 0x042B,
1026 b43legacy_phy_read(dev, 0x042B) | 0x0800);
1027 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1028 b43legacy_phy_read(dev,
1029 B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
1030
1031 phy_stacksave(0x04A0);
1032 b43legacy_phy_write(dev, 0x04A0,
1033 (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
1034 | 0x0008);
1035 phy_stacksave(0x04A1);
1036 b43legacy_phy_write(dev, 0x04A1,
1037 (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
1038 | 0x0605);
1039 phy_stacksave(0x04A2);
1040 b43legacy_phy_write(dev, 0x04A2,
1041 (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
1042 | 0x0204);
1043 phy_stacksave(0x04A8);
1044 b43legacy_phy_write(dev, 0x04A8,
1045 (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
1046 | 0x0803);
1047 phy_stacksave(0x04AB);
1048 b43legacy_phy_write(dev, 0x04AB,
1049 (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
1050 | 0x0605);
1051
1052 phy_stacksave(0x04A7);
1053 b43legacy_phy_write(dev, 0x04A7, 0x0002);
1054 phy_stacksave(0x04A3);
1055 b43legacy_phy_write(dev, 0x04A3, 0x287A);
1056 phy_stacksave(0x04A9);
1057 b43legacy_phy_write(dev, 0x04A9, 0x2027);
1058 phy_stacksave(0x0493);
1059 b43legacy_phy_write(dev, 0x0493, 0x32F5);
1060 phy_stacksave(0x04AA);
1061 b43legacy_phy_write(dev, 0x04AA, 0x2027);
1062 phy_stacksave(0x04AC);
1063 b43legacy_phy_write(dev, 0x04AC, 0x32F5);
1064 break;
1065 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1066 if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
1067 break;
1068
1069 phy->aci_enable = 1;
1070
1071 phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
1072 phy_stacksave(B43legacy_PHY_G_CRS);
1073 if (phy->rev < 2)
1074 phy_stacksave(0x0406);
1075 else {
1076 phy_stacksave(0x04C0);
1077 phy_stacksave(0x04C1);
1078 }
1079 phy_stacksave(0x0033);
1080 phy_stacksave(0x04A7);
1081 phy_stacksave(0x04A3);
1082 phy_stacksave(0x04A9);
1083 phy_stacksave(0x04AA);
1084 phy_stacksave(0x04AC);
1085 phy_stacksave(0x0493);
1086 phy_stacksave(0x04A1);
1087 phy_stacksave(0x04A0);
1088 phy_stacksave(0x04A2);
1089 phy_stacksave(0x048A);
1090 phy_stacksave(0x04A8);
1091 phy_stacksave(0x04AB);
1092 if (phy->rev == 2) {
1093 phy_stacksave(0x04AD);
1094 phy_stacksave(0x04AE);
1095 } else if (phy->rev >= 3) {
1096 phy_stacksave(0x04AD);
1097 phy_stacksave(0x0415);
1098 phy_stacksave(0x0416);
1099 phy_stacksave(0x0417);
1100 ilt_stacksave(0x1A00 + 0x2);
1101 ilt_stacksave(0x1A00 + 0x3);
1102 }
1103 phy_stacksave(0x042B);
1104 phy_stacksave(0x048C);
1105
1106 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1107 b43legacy_phy_read(dev,
1108 B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
1109 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1110 (b43legacy_phy_read(dev,
1111 B43legacy_PHY_G_CRS)
1112 & 0xFFFC) | 0x0002);
1113
1114 b43legacy_phy_write(dev, 0x0033, 0x0800);
1115 b43legacy_phy_write(dev, 0x04A3, 0x2027);
1116 b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
1117 b43legacy_phy_write(dev, 0x0493, 0x287A);
1118 b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
1119 b43legacy_phy_write(dev, 0x04AC, 0x287A);
1120
1121 b43legacy_phy_write(dev, 0x04A0,
1122 (b43legacy_phy_read(dev, 0x04A0)
1123 & 0xFFC0) | 0x001A);
1124 b43legacy_phy_write(dev, 0x04A7, 0x000D);
1125
1126 if (phy->rev < 2)
1127 b43legacy_phy_write(dev, 0x0406, 0xFF0D);
1128 else if (phy->rev == 2) {
1129 b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
1130 b43legacy_phy_write(dev, 0x04C1, 0x00A9);
1131 } else {
1132 b43legacy_phy_write(dev, 0x04C0, 0x00C1);
1133 b43legacy_phy_write(dev, 0x04C1, 0x0059);
1134 }
1135
1136 b43legacy_phy_write(dev, 0x04A1,
1137 (b43legacy_phy_read(dev, 0x04A1)
1138 & 0xC0FF) | 0x1800);
1139 b43legacy_phy_write(dev, 0x04A1,
1140 (b43legacy_phy_read(dev, 0x04A1)
1141 & 0xFFC0) | 0x0015);
1142 b43legacy_phy_write(dev, 0x04A8,
1143 (b43legacy_phy_read(dev, 0x04A8)
1144 & 0xCFFF) | 0x1000);
1145 b43legacy_phy_write(dev, 0x04A8,
1146 (b43legacy_phy_read(dev, 0x04A8)
1147 & 0xF0FF) | 0x0A00);
1148 b43legacy_phy_write(dev, 0x04AB,
1149 (b43legacy_phy_read(dev, 0x04AB)
1150 & 0xCFFF) | 0x1000);
1151 b43legacy_phy_write(dev, 0x04AB,
1152 (b43legacy_phy_read(dev, 0x04AB)
1153 & 0xF0FF) | 0x0800);
1154 b43legacy_phy_write(dev, 0x04AB,
1155 (b43legacy_phy_read(dev, 0x04AB)
1156 & 0xFFCF) | 0x0010);
1157 b43legacy_phy_write(dev, 0x04AB,
1158 (b43legacy_phy_read(dev, 0x04AB)
1159 & 0xFFF0) | 0x0005);
1160 b43legacy_phy_write(dev, 0x04A8,
1161 (b43legacy_phy_read(dev, 0x04A8)
1162 & 0xFFCF) | 0x0010);
1163 b43legacy_phy_write(dev, 0x04A8,
1164 (b43legacy_phy_read(dev, 0x04A8)
1165 & 0xFFF0) | 0x0006);
1166 b43legacy_phy_write(dev, 0x04A2,
1167 (b43legacy_phy_read(dev, 0x04A2)
1168 & 0xF0FF) | 0x0800);
1169 b43legacy_phy_write(dev, 0x04A0,
1170 (b43legacy_phy_read(dev, 0x04A0)
1171 & 0xF0FF) | 0x0500);
1172 b43legacy_phy_write(dev, 0x04A2,
1173 (b43legacy_phy_read(dev, 0x04A2)
1174 & 0xFFF0) | 0x000B);
1175
1176 if (phy->rev >= 3) {
1177 b43legacy_phy_write(dev, 0x048A,
1178 b43legacy_phy_read(dev, 0x048A)
1179 & ~0x8000);
1180 b43legacy_phy_write(dev, 0x0415,
1181 (b43legacy_phy_read(dev, 0x0415)
1182 & 0x8000) | 0x36D8);
1183 b43legacy_phy_write(dev, 0x0416,
1184 (b43legacy_phy_read(dev, 0x0416)
1185 & 0x8000) | 0x36D8);
1186 b43legacy_phy_write(dev, 0x0417,
1187 (b43legacy_phy_read(dev, 0x0417)
1188 & 0xFE00) | 0x016D);
1189 } else {
1190 b43legacy_phy_write(dev, 0x048A,
1191 b43legacy_phy_read(dev, 0x048A)
1192 | 0x1000);
1193 b43legacy_phy_write(dev, 0x048A,
1194 (b43legacy_phy_read(dev, 0x048A)
1195 & 0x9FFF) | 0x2000);
1196 tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1197 B43legacy_UCODEFLAGS_OFFSET);
1198 if (!(tmp32 & 0x800)) {
1199 tmp32 |= 0x800;
1200 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1201 B43legacy_UCODEFLAGS_OFFSET,
1202 tmp32);
1203 }
1204 }
1205 if (phy->rev >= 2)
1206 b43legacy_phy_write(dev, 0x042B,
1207 b43legacy_phy_read(dev, 0x042B)
1208 | 0x0800);
1209 b43legacy_phy_write(dev, 0x048C,
1210 (b43legacy_phy_read(dev, 0x048C)
1211 & 0xF0FF) | 0x0200);
1212 if (phy->rev == 2) {
1213 b43legacy_phy_write(dev, 0x04AE,
1214 (b43legacy_phy_read(dev, 0x04AE)
1215 & 0xFF00) | 0x007F);
1216 b43legacy_phy_write(dev, 0x04AD,
1217 (b43legacy_phy_read(dev, 0x04AD)
1218 & 0x00FF) | 0x1300);
1219 } else if (phy->rev >= 6) {
1220 b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
1221 b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
1222 b43legacy_phy_write(dev, 0x04AD,
1223 b43legacy_phy_read(dev, 0x04AD)
1224 & 0x00FF);
1225 }
1226 b43legacy_calc_nrssi_slope(dev);
1227 break;
1228 default:
1229 B43legacy_BUG_ON(1);
1230 }
1231}
1232
1233static void
1234b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
1235 int mode)
1236{
1237 struct b43legacy_phy *phy = &dev->phy;
1238 u32 tmp32;
1239 u32 *stack = phy->interfstack;
1240
1241 switch (mode) {
1242 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1243 if (phy->rev != 1) {
1244 b43legacy_phy_write(dev, 0x042B,
1245 b43legacy_phy_read(dev, 0x042B)
1246 & ~0x0800);
1247 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1248 b43legacy_phy_read(dev,
1249 B43legacy_PHY_G_CRS) | 0x4000);
1250 break;
1251 }
1252 phy_stackrestore(0x0078);
1253 b43legacy_calc_nrssi_threshold(dev);
1254 phy_stackrestore(0x0406);
1255 b43legacy_phy_write(dev, 0x042B,
1256 b43legacy_phy_read(dev, 0x042B) & ~0x0800);
1257 if (!dev->bad_frames_preempt)
1258 b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
1259 b43legacy_phy_read(dev,
1260 B43legacy_PHY_RADIO_BITFIELD)
1261 & ~(1 << 11));
1262 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1263 b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
1264 | 0x4000);
1265 phy_stackrestore(0x04A0);
1266 phy_stackrestore(0x04A1);
1267 phy_stackrestore(0x04A2);
1268 phy_stackrestore(0x04A8);
1269 phy_stackrestore(0x04AB);
1270 phy_stackrestore(0x04A7);
1271 phy_stackrestore(0x04A3);
1272 phy_stackrestore(0x04A9);
1273 phy_stackrestore(0x0493);
1274 phy_stackrestore(0x04AA);
1275 phy_stackrestore(0x04AC);
1276 break;
1277 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1278 if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
1279 break;
1280
1281 phy->aci_enable = 0;
1282
1283 phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
1284 phy_stackrestore(B43legacy_PHY_G_CRS);
1285 phy_stackrestore(0x0033);
1286 phy_stackrestore(0x04A3);
1287 phy_stackrestore(0x04A9);
1288 phy_stackrestore(0x0493);
1289 phy_stackrestore(0x04AA);
1290 phy_stackrestore(0x04AC);
1291 phy_stackrestore(0x04A0);
1292 phy_stackrestore(0x04A7);
1293 if (phy->rev >= 2) {
1294 phy_stackrestore(0x04C0);
1295 phy_stackrestore(0x04C1);
1296 } else
1297 phy_stackrestore(0x0406);
1298 phy_stackrestore(0x04A1);
1299 phy_stackrestore(0x04AB);
1300 phy_stackrestore(0x04A8);
1301 if (phy->rev == 2) {
1302 phy_stackrestore(0x04AD);
1303 phy_stackrestore(0x04AE);
1304 } else if (phy->rev >= 3) {
1305 phy_stackrestore(0x04AD);
1306 phy_stackrestore(0x0415);
1307 phy_stackrestore(0x0416);
1308 phy_stackrestore(0x0417);
1309 ilt_stackrestore(0x1A00 + 0x2);
1310 ilt_stackrestore(0x1A00 + 0x3);
1311 }
1312 phy_stackrestore(0x04A2);
1313 phy_stackrestore(0x04A8);
1314 phy_stackrestore(0x042B);
1315 phy_stackrestore(0x048C);
1316 tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
1317 B43legacy_UCODEFLAGS_OFFSET);
1318 if (tmp32 & 0x800) {
1319 tmp32 &= ~0x800;
1320 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1321 B43legacy_UCODEFLAGS_OFFSET,
1322 tmp32);
1323 }
1324 b43legacy_calc_nrssi_slope(dev);
1325 break;
1326 default:
1327 B43legacy_BUG_ON(1);
1328 }
1329}
1330
1331#undef phy_stacksave
1332#undef phy_stackrestore
1333#undef radio_stacksave
1334#undef radio_stackrestore
1335#undef ilt_stacksave
1336#undef ilt_stackrestore
1337
1338int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
1339 int mode)
1340{
1341 struct b43legacy_phy *phy = &dev->phy;
1342 int currentmode;
1343
1344 if ((phy->type != B43legacy_PHYTYPE_G) ||
1345 (phy->rev == 0) || (!phy->gmode))
1346 return -ENODEV;
1347
1348 phy->aci_wlan_automatic = 0;
1349 switch (mode) {
1350 case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
1351 phy->aci_wlan_automatic = 1;
1352 if (phy->aci_enable)
1353 mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
1354 else
1355 mode = B43legacy_RADIO_INTERFMODE_NONE;
1356 break;
1357 case B43legacy_RADIO_INTERFMODE_NONE:
1358 case B43legacy_RADIO_INTERFMODE_NONWLAN:
1359 case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
1360 break;
1361 default:
1362 return -EINVAL;
1363 }
1364
1365 currentmode = phy->interfmode;
1366 if (currentmode == mode)
1367 return 0;
1368 if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
1369 b43legacy_radio_interference_mitigation_disable(dev,
1370 currentmode);
1371
1372 if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
1373 phy->aci_enable = 0;
1374 phy->aci_hw_rssi = 0;
1375 } else
1376 b43legacy_radio_interference_mitigation_enable(dev, mode);
1377 phy->interfmode = mode;
1378
1379 return 0;
1380}
1381
1382u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
1383{
1384 u16 reg;
1385 u16 index;
1386 u16 ret;
1387
1388 reg = b43legacy_radio_read16(dev, 0x0060);
1389 index = (reg & 0x001E) >> 1;
1390 ret = rcc_table[index] << 1;
1391 ret |= (reg & 0x0001);
1392 ret |= 0x0020;
1393
1394 return ret;
1395}
1396
1397#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
1398static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
1399{
1400 struct b43legacy_phy *phy = &dev->phy;
1401 u16 loop_or = 0;
1402 u16 adj_loopback_gain = phy->loopback_gain[0];
1403 u8 loop;
1404 u16 extern_lna_control;
1405
1406 if (!phy->gmode)
1407 return 0;
1408 if (!has_loopback_gain(phy)) {
1409 if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo
1410 & B43legacy_BFL_EXTLNA)) {
1411 switch (lpd) {
1412 case LPD(0, 1, 1):
1413 return 0x0FB2;
1414 case LPD(0, 0, 1):
1415 return 0x00B2;
1416 case LPD(1, 0, 1):
1417 return 0x30B2;
1418 case LPD(1, 0, 0):
1419 return 0x30B3;
1420 default:
1421 B43legacy_BUG_ON(1);
1422 }
1423 } else {
1424 switch (lpd) {
1425 case LPD(0, 1, 1):
1426 return 0x8FB2;
1427 case LPD(0, 0, 1):
1428 return 0x80B2;
1429 case LPD(1, 0, 1):
1430 return 0x20B2;
1431 case LPD(1, 0, 0):
1432 return 0x20B3;
1433 default:
1434 B43legacy_BUG_ON(1);
1435 }
1436 }
1437 } else {
1438 if (phy->radio_rev == 8)
1439 adj_loopback_gain += 0x003E;
1440 else
1441 adj_loopback_gain += 0x0026;
1442 if (adj_loopback_gain >= 0x46) {
1443 adj_loopback_gain -= 0x46;
1444 extern_lna_control = 0x3000;
1445 } else if (adj_loopback_gain >= 0x3A) {
1446 adj_loopback_gain -= 0x3A;
1447 extern_lna_control = 0x2000;
1448 } else if (adj_loopback_gain >= 0x2E) {
1449 adj_loopback_gain -= 0x2E;
1450 extern_lna_control = 0x1000;
1451 } else {
1452 adj_loopback_gain -= 0x10;
1453 extern_lna_control = 0x0000;
1454 }
1455 for (loop = 0; loop < 16; loop++) {
1456 u16 tmp = adj_loopback_gain - 6 * loop;
1457 if (tmp < 6)
1458 break;
1459 }
1460
1461 loop_or = (loop << 8) | extern_lna_control;
1462 if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo
1463 & B43legacy_BFL_EXTLNA) {
1464 if (extern_lna_control)
1465 loop_or |= 0x8000;
1466 switch (lpd) {
1467 case LPD(0, 1, 1):
1468 return 0x8F92;
1469 case LPD(0, 0, 1):
1470 return (0x8092 | loop_or);
1471 case LPD(1, 0, 1):
1472 return (0x2092 | loop_or);
1473 case LPD(1, 0, 0):
1474 return (0x2093 | loop_or);
1475 default:
1476 B43legacy_BUG_ON(1);
1477 }
1478 } else {
1479 switch (lpd) {
1480 case LPD(0, 1, 1):
1481 return 0x0F92;
1482 case LPD(0, 0, 1):
1483 case LPD(1, 0, 1):
1484 return (0x0092 | loop_or);
1485 case LPD(1, 0, 0):
1486 return (0x0093 | loop_or);
1487 default:
1488 B43legacy_BUG_ON(1);
1489 }
1490 }
1491 }
1492 return 0;
1493}
1494
1495u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
1496{
1497 struct b43legacy_phy *phy = &dev->phy;
1498 u16 backup[21] = { 0 };
1499 u16 ret;
1500 u16 i;
1501 u16 j;
1502 u32 tmp1 = 0;
1503 u32 tmp2 = 0;
1504
1505 backup[0] = b43legacy_radio_read16(dev, 0x0043);
1506 backup[14] = b43legacy_radio_read16(dev, 0x0051);
1507 backup[15] = b43legacy_radio_read16(dev, 0x0052);
1508 backup[1] = b43legacy_phy_read(dev, 0x0015);
1509 backup[16] = b43legacy_phy_read(dev, 0x005A);
1510 backup[17] = b43legacy_phy_read(dev, 0x0059);
1511 backup[18] = b43legacy_phy_read(dev, 0x0058);
1512 if (phy->type == B43legacy_PHYTYPE_B) {
1513 backup[2] = b43legacy_phy_read(dev, 0x0030);
1514 backup[3] = b43legacy_read16(dev, 0x03EC);
1515 b43legacy_phy_write(dev, 0x0030, 0x00FF);
1516 b43legacy_write16(dev, 0x03EC, 0x3F3F);
1517 } else {
1518 if (phy->gmode) {
1519 backup[4] = b43legacy_phy_read(dev, 0x0811);
1520 backup[5] = b43legacy_phy_read(dev, 0x0812);
1521 backup[6] = b43legacy_phy_read(dev, 0x0814);
1522 backup[7] = b43legacy_phy_read(dev, 0x0815);
1523 backup[8] = b43legacy_phy_read(dev,
1524 B43legacy_PHY_G_CRS);
1525 backup[9] = b43legacy_phy_read(dev, 0x0802);
1526 b43legacy_phy_write(dev, 0x0814,
1527 (b43legacy_phy_read(dev, 0x0814)
1528 | 0x0003));
1529 b43legacy_phy_write(dev, 0x0815,
1530 (b43legacy_phy_read(dev, 0x0815)
1531 & 0xFFFC));
1532 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1533 (b43legacy_phy_read(dev,
1534 B43legacy_PHY_G_CRS) & 0x7FFF));
1535 b43legacy_phy_write(dev, 0x0802,
1536 (b43legacy_phy_read(dev, 0x0802)
1537 & 0xFFFC));
1538 if (phy->rev > 1) { /* loopback gain enabled */
1539 backup[19] = b43legacy_phy_read(dev, 0x080F);
1540 backup[20] = b43legacy_phy_read(dev, 0x0810);
1541 if (phy->rev >= 3)
1542 b43legacy_phy_write(dev, 0x080F,
1543 0xC020);
1544 else
1545 b43legacy_phy_write(dev, 0x080F,
1546 0x8020);
1547 b43legacy_phy_write(dev, 0x0810, 0x0000);
1548 }
1549 b43legacy_phy_write(dev, 0x0812,
1550 b43legacy_get_812_value(dev,
1551 LPD(0, 1, 1)));
1552 if (phy->rev < 7 ||
1553 !(dev->dev->bus->sprom.r1.boardflags_lo
1554 & B43legacy_BFL_EXTLNA))
1555 b43legacy_phy_write(dev, 0x0811, 0x01B3);
1556 else
1557 b43legacy_phy_write(dev, 0x0811, 0x09B3);
1558 }
1559 }
1560 b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1561 (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
1562 | 0x8000));
1563 backup[10] = b43legacy_phy_read(dev, 0x0035);
1564 b43legacy_phy_write(dev, 0x0035,
1565 (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
1566 backup[11] = b43legacy_read16(dev, 0x03E6);
1567 backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
1568
1569 /* Initialization */
1570 if (phy->analog == 0)
1571 b43legacy_write16(dev, 0x03E6, 0x0122);
1572 else {
1573 if (phy->analog >= 2)
1574 b43legacy_phy_write(dev, 0x0003,
1575 (b43legacy_phy_read(dev, 0x0003)
1576 & 0xFFBF) | 0x0040);
1577 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1578 (b43legacy_read16(dev,
1579 B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
1580 }
1581
1582 ret = b43legacy_radio_calibrationvalue(dev);
1583
1584 if (phy->type == B43legacy_PHYTYPE_B)
1585 b43legacy_radio_write16(dev, 0x0078, 0x0026);
1586
1587 if (phy->gmode)
1588 b43legacy_phy_write(dev, 0x0812,
1589 b43legacy_get_812_value(dev,
1590 LPD(0, 1, 1)));
1591 b43legacy_phy_write(dev, 0x0015, 0xBFAF);
1592 b43legacy_phy_write(dev, 0x002B, 0x1403);
1593 if (phy->gmode)
1594 b43legacy_phy_write(dev, 0x0812,
1595 b43legacy_get_812_value(dev,
1596 LPD(0, 0, 1)));
1597 b43legacy_phy_write(dev, 0x0015, 0xBFA0);
1598 b43legacy_radio_write16(dev, 0x0051,
1599 (b43legacy_radio_read16(dev, 0x0051)
1600 | 0x0004));
1601 if (phy->radio_rev == 8)
1602 b43legacy_radio_write16(dev, 0x0043, 0x001F);
1603 else {
1604 b43legacy_radio_write16(dev, 0x0052, 0x0000);
1605 b43legacy_radio_write16(dev, 0x0043,
1606 (b43legacy_radio_read16(dev, 0x0043)
1607 & 0xFFF0) | 0x0009);
1608 }
1609 b43legacy_phy_write(dev, 0x0058, 0x0000);
1610
1611 for (i = 0; i < 16; i++) {
1612 b43legacy_phy_write(dev, 0x005A, 0x0480);
1613 b43legacy_phy_write(dev, 0x0059, 0xC810);
1614 b43legacy_phy_write(dev, 0x0058, 0x000D);
1615 if (phy->gmode)
1616 b43legacy_phy_write(dev, 0x0812,
1617 b43legacy_get_812_value(dev,
1618 LPD(1, 0, 1)));
1619 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1620 udelay(10);
1621 if (phy->gmode)
1622 b43legacy_phy_write(dev, 0x0812,
1623 b43legacy_get_812_value(dev,
1624 LPD(1, 0, 1)));
1625 b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1626 udelay(10);
1627 if (phy->gmode)
1628 b43legacy_phy_write(dev, 0x0812,
1629 b43legacy_get_812_value(dev,
1630 LPD(1, 0, 0)));
1631 b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1632 udelay(20);
1633 tmp1 += b43legacy_phy_read(dev, 0x002D);
1634 b43legacy_phy_write(dev, 0x0058, 0x0000);
1635 if (phy->gmode)
1636 b43legacy_phy_write(dev, 0x0812,
1637 b43legacy_get_812_value(dev,
1638 LPD(1, 0, 1)));
1639 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1640 }
1641
1642 tmp1++;
1643 tmp1 >>= 9;
1644 udelay(10);
1645 b43legacy_phy_write(dev, 0x0058, 0x0000);
1646
1647 for (i = 0; i < 16; i++) {
1648 b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
1649 | 0x0020);
1650 backup[13] = b43legacy_radio_read16(dev, 0x0078);
1651 udelay(10);
1652 for (j = 0; j < 16; j++) {
1653 b43legacy_phy_write(dev, 0x005A, 0x0D80);
1654 b43legacy_phy_write(dev, 0x0059, 0xC810);
1655 b43legacy_phy_write(dev, 0x0058, 0x000D);
1656 if (phy->gmode)
1657 b43legacy_phy_write(dev, 0x0812,
1658 b43legacy_get_812_value(dev,
1659 LPD(1, 0, 1)));
1660 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1661 udelay(10);
1662 if (phy->gmode)
1663 b43legacy_phy_write(dev, 0x0812,
1664 b43legacy_get_812_value(dev,
1665 LPD(1, 0, 1)));
1666 b43legacy_phy_write(dev, 0x0015, 0xEFB0);
1667 udelay(10);
1668 if (phy->gmode)
1669 b43legacy_phy_write(dev, 0x0812,
1670 b43legacy_get_812_value(dev,
1671 LPD(1, 0, 0)));
1672 b43legacy_phy_write(dev, 0x0015, 0xFFF0);
1673 udelay(10);
1674 tmp2 += b43legacy_phy_read(dev, 0x002D);
1675 b43legacy_phy_write(dev, 0x0058, 0x0000);
1676 if (phy->gmode)
1677 b43legacy_phy_write(dev, 0x0812,
1678 b43legacy_get_812_value(dev,
1679 LPD(1, 0, 1)));
1680 b43legacy_phy_write(dev, 0x0015, 0xAFB0);
1681 }
1682 tmp2++;
1683 tmp2 >>= 8;
1684 if (tmp1 < tmp2)
1685 break;
1686 }
1687
1688 /* Restore the registers */
1689 b43legacy_phy_write(dev, 0x0015, backup[1]);
1690 b43legacy_radio_write16(dev, 0x0051, backup[14]);
1691 b43legacy_radio_write16(dev, 0x0052, backup[15]);
1692 b43legacy_radio_write16(dev, 0x0043, backup[0]);
1693 b43legacy_phy_write(dev, 0x005A, backup[16]);
1694 b43legacy_phy_write(dev, 0x0059, backup[17]);
1695 b43legacy_phy_write(dev, 0x0058, backup[18]);
1696 b43legacy_write16(dev, 0x03E6, backup[11]);
1697 if (phy->analog != 0)
1698 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
1699 b43legacy_phy_write(dev, 0x0035, backup[10]);
1700 b43legacy_radio_selectchannel(dev, phy->channel, 1);
1701 if (phy->type == B43legacy_PHYTYPE_B) {
1702 b43legacy_phy_write(dev, 0x0030, backup[2]);
1703 b43legacy_write16(dev, 0x03EC, backup[3]);
1704 } else {
1705 if (phy->gmode) {
1706 b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
1707 (b43legacy_read16(dev,
1708 B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
1709 b43legacy_phy_write(dev, 0x0811, backup[4]);
1710 b43legacy_phy_write(dev, 0x0812, backup[5]);
1711 b43legacy_phy_write(dev, 0x0814, backup[6]);
1712 b43legacy_phy_write(dev, 0x0815, backup[7]);
1713 b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
1714 backup[8]);
1715 b43legacy_phy_write(dev, 0x0802, backup[9]);
1716 if (phy->rev > 1) {
1717 b43legacy_phy_write(dev, 0x080F, backup[19]);
1718 b43legacy_phy_write(dev, 0x0810, backup[20]);
1719 }
1720 }
1721 }
1722 if (i >= 15)
1723 ret = backup[13];
1724
1725 return ret;
1726}
1727
1728static inline
1729u16 freq_r3A_value(u16 frequency)
1730{
1731 u16 value;
1732
1733 if (frequency < 5091)
1734 value = 0x0040;
1735 else if (frequency < 5321)
1736 value = 0x0000;
1737 else if (frequency < 5806)
1738 value = 0x0080;
1739 else
1740 value = 0x0040;
1741
1742 return value;
1743}
1744
1745void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev)
1746{
1747 static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
1748 static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
1749 u16 tmp = b43legacy_radio_read16(dev, 0x001E);
1750 int i;
1751 int j;
1752
1753 for (i = 0; i < 5; i++) {
1754 for (j = 0; j < 5; j++) {
1755 if (tmp == (data_high[i] | data_low[j])) {
1756 b43legacy_phy_write(dev, 0x0069, (i - j) << 8 |
1757 0x00C0);
1758 return;
1759 }
1760 }
1761 }
1762}
1763
1764int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
1765 u8 channel,
1766 int synthetic_pu_workaround)
1767{
1768 struct b43legacy_phy *phy = &dev->phy;
1769
1770/* TODO: Check if channel is valid - return -EINVAL if not */
1771 if (synthetic_pu_workaround)
1772 b43legacy_synth_pu_workaround(dev, channel);
1773
1774 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
1775 channel2freq_bg(channel));
1776
1777 if (channel == 14) {
1778 if (dev->dev->bus->sprom.r1.country_code == 5) /* JAPAN) */
1779 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1780 B43legacy_UCODEFLAGS_OFFSET,
1781 b43legacy_shm_read32(dev,
1782 B43legacy_SHM_SHARED,
1783 B43legacy_UCODEFLAGS_OFFSET)
1784 & ~(1 << 7));
1785 else
1786 b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
1787 B43legacy_UCODEFLAGS_OFFSET,
1788 b43legacy_shm_read32(dev,
1789 B43legacy_SHM_SHARED,
1790 B43legacy_UCODEFLAGS_OFFSET)
1791 | (1 << 7));
1792 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1793 b43legacy_read16(dev,
1794 B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
1795 } else
1796 b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
1797 b43legacy_read16(dev,
1798 B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
1799
1800 phy->channel = channel;
1801 /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
1802 * that 2000 usecs might suffice. */
1803 msleep(8);
1804
1805 return 0;
1806}
1807
1808void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
1809{
1810 u16 tmp;
1811
1812 val <<= 8;
1813 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
1814 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
1815 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
1816 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
1817 tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
1818 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
1819}
1820
1821/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
1822static u16 b43legacy_get_txgain_base_band(u16 txpower)
1823{
1824 u16 ret;
1825
1826 B43legacy_WARN_ON(txpower > 63);
1827
1828 if (txpower >= 54)
1829 ret = 2;
1830 else if (txpower >= 49)
1831 ret = 4;
1832 else if (txpower >= 44)
1833 ret = 5;
1834 else
1835 ret = 6;
1836
1837 return ret;
1838}
1839
1840/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
1841static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
1842{
1843 u16 ret;
1844
1845 B43legacy_WARN_ON(txpower > 63);
1846
1847 if (txpower >= 32)
1848 ret = 0;
1849 else if (txpower >= 25)
1850 ret = 1;
1851 else if (txpower >= 20)
1852 ret = 2;
1853 else if (txpower >= 12)
1854 ret = 3;
1855 else
1856 ret = 4;
1857
1858 return ret;
1859}
1860
1861/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
1862static u16 b43legacy_get_txgain_dac(u16 txpower)
1863{
1864 u16 ret;
1865
1866 B43legacy_WARN_ON(txpower > 63);
1867
1868 if (txpower >= 54)
1869 ret = txpower - 53;
1870 else if (txpower >= 49)
1871 ret = txpower - 42;
1872 else if (txpower >= 44)
1873 ret = txpower - 37;
1874 else if (txpower >= 32)
1875 ret = txpower - 32;
1876 else if (txpower >= 25)
1877 ret = txpower - 20;
1878 else if (txpower >= 20)
1879 ret = txpower - 13;
1880 else if (txpower >= 12)
1881 ret = txpower - 8;
1882 else
1883 ret = txpower;
1884
1885 return ret;
1886}
1887
1888void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
1889{
1890 struct b43legacy_phy *phy = &dev->phy;
1891 u16 pamp;
1892 u16 base;
1893 u16 dac;
1894 u16 ilt;
1895
1896 txpower = limit_value(txpower, 0, 63);
1897
1898 pamp = b43legacy_get_txgain_freq_power_amp(txpower);
1899 pamp <<= 5;
1900 pamp &= 0x00E0;
1901 b43legacy_phy_write(dev, 0x0019, pamp);
1902
1903 base = b43legacy_get_txgain_base_band(txpower);
1904 base &= 0x000F;
1905 b43legacy_phy_write(dev, 0x0017, base | 0x0020);
1906
1907 ilt = b43legacy_ilt_read(dev, 0x3001);
1908 ilt &= 0x0007;
1909
1910 dac = b43legacy_get_txgain_dac(txpower);
1911 dac <<= 3;
1912 dac |= ilt;
1913
1914 b43legacy_ilt_write(dev, 0x3001, dac);
1915
1916 phy->txpwr_offset = txpower;
1917
1918 /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
1919}
1920
1921void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
1922 u16 baseband_attenuation,
1923 u16 radio_attenuation,
1924 u16 txpower)
1925{
1926 struct b43legacy_phy *phy = &dev->phy;
1927
1928 if (baseband_attenuation == 0xFFFF)
1929 baseband_attenuation = phy->bbatt;
1930 if (radio_attenuation == 0xFFFF)
1931 radio_attenuation = phy->rfatt;
1932 if (txpower == 0xFFFF)
1933 txpower = phy->txctl1;
1934 phy->bbatt = baseband_attenuation;
1935 phy->rfatt = radio_attenuation;
1936 phy->txctl1 = txpower;
1937
1938 B43legacy_WARN_ON(baseband_attenuation > 11);
1939 if (phy->radio_rev < 6)
1940 B43legacy_WARN_ON(radio_attenuation > 9);
1941 else
1942 B43legacy_WARN_ON(radio_attenuation > 31);
1943 B43legacy_WARN_ON(txpower > 7);
1944
1945 b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
1946 b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
1947 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
1948 radio_attenuation);
1949 if (phy->radio_ver == 0x2050)
1950 b43legacy_radio_write16(dev, 0x0052,
1951 (b43legacy_radio_read16(dev, 0x0052)
1952 & ~0x0070) | ((txpower << 4) & 0x0070));
1953 /* FIXME: The spec is very weird and unclear here. */
1954 if (phy->type == B43legacy_PHYTYPE_G)
1955 b43legacy_phy_lo_adjust(dev, 0);
1956}
1957
1958u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
1959{
1960 struct b43legacy_phy *phy = &dev->phy;
1961
1962 if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
1963 return 0;
1964 return 2;
1965}
1966
1967u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
1968{
1969 struct b43legacy_phy *phy = &dev->phy;
1970 u16 att = 0xFFFF;
1971
1972 switch (phy->radio_ver) {
1973 case 0x2053:
1974 switch (phy->radio_rev) {
1975 case 1:
1976 att = 6;
1977 break;
1978 }
1979 break;
1980 case 0x2050:
1981 switch (phy->radio_rev) {
1982 case 0:
1983 att = 5;
1984 break;
1985 case 1:
1986 if (phy->type == B43legacy_PHYTYPE_G) {
1987 if (is_bcm_board_vendor(dev) &&
1988 dev->dev->bus->boardinfo.type == 0x421 &&
1989 dev->dev->bus->boardinfo.rev >= 30)
1990 att = 3;
1991 else if (is_bcm_board_vendor(dev) &&
1992 dev->dev->bus->boardinfo.type == 0x416)
1993 att = 3;
1994 else
1995 att = 1;
1996 } else {
1997 if (is_bcm_board_vendor(dev) &&
1998 dev->dev->bus->boardinfo.type == 0x421 &&
1999 dev->dev->bus->boardinfo.rev >= 30)
2000 att = 7;
2001 else
2002 att = 6;
2003 }
2004 break;
2005 case 2:
2006 if (phy->type == B43legacy_PHYTYPE_G) {
2007 if (is_bcm_board_vendor(dev) &&
2008 dev->dev->bus->boardinfo.type == 0x421 &&
2009 dev->dev->bus->boardinfo.rev >= 30)
2010 att = 3;
2011 else if (is_bcm_board_vendor(dev) &&
2012 dev->dev->bus->boardinfo.type ==
2013 0x416)
2014 att = 5;
2015 else if (dev->dev->bus->chip_id == 0x4320)
2016 att = 4;
2017 else
2018 att = 3;
2019 } else
2020 att = 6;
2021 break;
2022 case 3:
2023 att = 5;
2024 break;
2025 case 4:
2026 case 5:
2027 att = 1;
2028 break;
2029 case 6:
2030 case 7:
2031 att = 5;
2032 break;
2033 case 8:
2034 att = 0x1A;
2035 break;
2036 case 9:
2037 default:
2038 att = 5;
2039 }
2040 }
2041 if (is_bcm_board_vendor(dev) &&
2042 dev->dev->bus->boardinfo.type == 0x421) {
2043 if (dev->dev->bus->boardinfo.rev < 0x43)
2044 att = 2;
2045 else if (dev->dev->bus->boardinfo.rev < 0x51)
2046 att = 3;
2047 }
2048 if (att == 0xFFFF)
2049 att = 5;
2050
2051 return att;
2052}
2053
2054u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
2055{
2056 struct b43legacy_phy *phy = &dev->phy;
2057
2058 if (phy->radio_ver != 0x2050)
2059 return 0;
2060 if (phy->radio_rev == 1)
2061 return 3;
2062 if (phy->radio_rev < 6)
2063 return 2;
2064 if (phy->radio_rev == 8)
2065 return 1;
2066 return 0;
2067}
2068
2069void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
2070{
2071 struct b43legacy_phy *phy = &dev->phy;
2072 int err;
2073
2074 might_sleep();
2075
2076 if (phy->radio_on)
2077 return;
2078
2079 switch (phy->type) {
2080 case B43legacy_PHYTYPE_B:
2081 case B43legacy_PHYTYPE_G:
2082 b43legacy_phy_write(dev, 0x0015, 0x8000);
2083 b43legacy_phy_write(dev, 0x0015, 0xCC00);
2084 b43legacy_phy_write(dev, 0x0015,
2085 (phy->gmode ? 0x00C0 : 0x0000));
2086 err = b43legacy_radio_selectchannel(dev,
2087 B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
2088 B43legacy_WARN_ON(err != 0);
2089 break;
2090 default:
2091 B43legacy_BUG_ON(1);
2092 }
2093 phy->radio_on = 1;
2094 b43legacydbg(dev->wl, "Radio turned on\n");
2095 b43legacy_leds_update(dev, 0);
2096}
2097
2098void b43legacy_radio_turn_off(struct b43legacy_wldev *dev)
2099{
2100 struct b43legacy_phy *phy = &dev->phy;
2101
2102 if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
2103 b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811)
2104 | 0x008C);
2105 b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812)
2106 & 0xFF73);
2107 } else
2108 b43legacy_phy_write(dev, 0x0015, 0xAA00);
2109 phy->radio_on = 0;
2110 b43legacydbg(dev->wl, "Radio turned off\n");
2111 b43legacy_leds_update(dev, 0);
2112}
2113
2114void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
2115{
2116 struct b43legacy_phy *phy = &dev->phy;
2117
2118 switch (phy->type) {
2119 case B43legacy_PHYTYPE_B:
2120 case B43legacy_PHYTYPE_G:
2121 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
2122 0x7F7F);
2123 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
2124 0x7F7F);
2125 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
2126 0x7F7F);
2127 b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
2128 0x7F7F);
2129 break;
2130 }
2131}
diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h
new file mode 100644
index 00000000000..6c6a203439e
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.h
@@ -0,0 +1,98 @@
1/*
2
3 Broadcom B43legacy 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 B43legacy_RADIO_H_
32#define B43legacy_RADIO_H_
33
34#include "b43legacy.h"
35
36
37#define B43legacy_RADIO_DEFAULT_CHANNEL_BG 6
38
39/* Force antenna 0. */
40#define B43legacy_RADIO_TXANTENNA_0 0
41/* Force antenna 1. */
42#define B43legacy_RADIO_TXANTENNA_1 1
43/* Use the RX antenna, that was selected for the most recently
44 * received good PLCP header.
45 */
46#define B43legacy_RADIO_TXANTENNA_LASTPLCP 3
47#define B43legacy_RADIO_TXANTENNA_DEFAULT B43legacy_RADIO_TXANTENNA_LASTPLCP
48
49#define B43legacy_RADIO_INTERFMODE_NONE 0
50#define B43legacy_RADIO_INTERFMODE_NONWLAN 1
51#define B43legacy_RADIO_INTERFMODE_MANUALWLAN 2
52#define B43legacy_RADIO_INTERFMODE_AUTOWLAN 3
53
54
55void b43legacy_radio_lock(struct b43legacy_wldev *dev);
56void b43legacy_radio_unlock(struct b43legacy_wldev *dev);
57
58u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset);
59void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val);
60
61u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev);
62
63void b43legacy_radio_turn_on(struct b43legacy_wldev *dev);
64void b43legacy_radio_turn_off(struct b43legacy_wldev *dev);
65
66int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel,
67 int synthetic_pu_workaround);
68
69void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower);
70void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
71 u16 baseband_attenuation, u16 attenuation,
72 u16 txpower);
73
74u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev);
75u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev);
76u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev);
77
78void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val);
79
80void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev);
81
82u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel);
83u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev);
84
85int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
86 int mode);
87
88void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev);
89void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev);
90s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset);
91void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val);
92void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val);
93void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev);
94
95void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev);
96u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev);
97
98#endif /* B43legacy_RADIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c
new file mode 100644
index 00000000000..56c384fa9b1
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.c
@@ -0,0 +1,238 @@
1/*
2
3 Broadcom B43legacy wireless driver
4
5 SYSFS support routines
6
7 Copyright (c) 2006 Michael Buesch <mb@bu3sch.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 "sysfs.h"
27#include "b43legacy.h"
28#include "main.h"
29#include "phy.h"
30#include "radio.h"
31
32#include <linux/capability.h>
33
34
35#define GENERIC_FILESIZE 64
36
37
38static int get_integer(const char *buf, size_t count)
39{
40 char tmp[10 + 1] = { 0 };
41 int ret = -EINVAL;
42
43 if (count == 0)
44 goto out;
45 count = min(count, (size_t)10);
46 memcpy(tmp, buf, count);
47 ret = simple_strtol(tmp, NULL, 10);
48out:
49 return ret;
50}
51
52static int get_boolean(const char *buf, size_t count)
53{
54 if (count != 0) {
55 if (buf[0] == '1')
56 return 1;
57 if (buf[0] == '0')
58 return 0;
59 if (count >= 4 && memcmp(buf, "true", 4) == 0)
60 return 1;
61 if (count >= 5 && memcmp(buf, "false", 5) == 0)
62 return 0;
63 if (count >= 3 && memcmp(buf, "yes", 3) == 0)
64 return 1;
65 if (count >= 2 && memcmp(buf, "no", 2) == 0)
66 return 0;
67 if (count >= 2 && memcmp(buf, "on", 2) == 0)
68 return 1;
69 if (count >= 3 && memcmp(buf, "off", 3) == 0)
70 return 0;
71 }
72 return -EINVAL;
73}
74
75static ssize_t b43legacy_attr_interfmode_show(struct device *dev,
76 struct device_attribute *attr,
77 char *buf)
78{
79 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
80 ssize_t count = 0;
81
82 if (!capable(CAP_NET_ADMIN))
83 return -EPERM;
84
85 mutex_lock(&wldev->wl->mutex);
86
87 switch (wldev->phy.interfmode) {
88 case B43legacy_INTERFMODE_NONE:
89 count = snprintf(buf, PAGE_SIZE, "0 (No Interference"
90 " Mitigation)\n");
91 break;
92 case B43legacy_INTERFMODE_NONWLAN:
93 count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference"
94 " Mitigation)\n");
95 break;
96 case B43legacy_INTERFMODE_MANUALWLAN:
97 count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference"
98 " Mitigation)\n");
99 break;
100 default:
101 B43legacy_WARN_ON(1);
102 }
103
104 mutex_unlock(&wldev->wl->mutex);
105
106 return count;
107}
108
109static ssize_t b43legacy_attr_interfmode_store(struct device *dev,
110 struct device_attribute *attr,
111 const char *buf, size_t count)
112{
113 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
114 unsigned long flags;
115 int err;
116 int mode;
117
118 if (!capable(CAP_NET_ADMIN))
119 return -EPERM;
120
121 mode = get_integer(buf, count);
122 switch (mode) {
123 case 0:
124 mode = B43legacy_INTERFMODE_NONE;
125 break;
126 case 1:
127 mode = B43legacy_INTERFMODE_NONWLAN;
128 break;
129 case 2:
130 mode = B43legacy_INTERFMODE_MANUALWLAN;
131 break;
132 case 3:
133 mode = B43legacy_INTERFMODE_AUTOWLAN;
134 break;
135 default:
136 return -EINVAL;
137 }
138
139 mutex_lock(&wldev->wl->mutex);
140 spin_lock_irqsave(&wldev->wl->irq_lock, flags);
141
142 err = b43legacy_radio_set_interference_mitigation(wldev, mode);
143 if (err)
144 b43legacyerr(wldev->wl, "Interference Mitigation not "
145 "supported by device\n");
146 mmiowb();
147 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
148 mutex_unlock(&wldev->wl->mutex);
149
150 return err ? err : count;
151}
152
153static DEVICE_ATTR(interference, 0644,
154 b43legacy_attr_interfmode_show,
155 b43legacy_attr_interfmode_store);
156
157static ssize_t b43legacy_attr_preamble_show(struct device *dev,
158 struct device_attribute *attr,
159 char *buf)
160{
161 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
162 ssize_t count;
163
164 if (!capable(CAP_NET_ADMIN))
165 return -EPERM;
166
167 mutex_lock(&wldev->wl->mutex);
168
169 if (wldev->short_preamble)
170 count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble"
171 " enabled)\n");
172 else
173 count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble"
174 " disabled)\n");
175
176 mutex_unlock(&wldev->wl->mutex);
177
178 return count;
179}
180
181static ssize_t b43legacy_attr_preamble_store(struct device *dev,
182 struct device_attribute *attr,
183 const char *buf, size_t count)
184{
185 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
186 unsigned long flags;
187 int value;
188
189 if (!capable(CAP_NET_ADMIN))
190 return -EPERM;
191
192 value = get_boolean(buf, count);
193 if (value < 0)
194 return value;
195 mutex_lock(&wldev->wl->mutex);
196 spin_lock_irqsave(&wldev->wl->irq_lock, flags);
197
198 wldev->short_preamble = !!value;
199
200 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
201 mutex_unlock(&wldev->wl->mutex);
202
203 return count;
204}
205
206static DEVICE_ATTR(shortpreamble, 0644,
207 b43legacy_attr_preamble_show,
208 b43legacy_attr_preamble_store);
209
210int b43legacy_sysfs_register(struct b43legacy_wldev *wldev)
211{
212 struct device *dev = wldev->dev->dev;
213 int err;
214
215 B43legacy_WARN_ON(b43legacy_status(wldev) !=
216 B43legacy_STAT_INITIALIZED);
217
218 err = device_create_file(dev, &dev_attr_interference);
219 if (err)
220 goto out;
221 err = device_create_file(dev, &dev_attr_shortpreamble);
222 if (err)
223 goto err_remove_interfmode;
224
225out:
226 return err;
227err_remove_interfmode:
228 device_remove_file(dev, &dev_attr_interference);
229 goto out;
230}
231
232void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev)
233{
234 struct device *dev = wldev->dev->dev;
235
236 device_remove_file(dev, &dev_attr_shortpreamble);
237 device_remove_file(dev, &dev_attr_interference);
238}
diff --git a/drivers/net/wireless/b43legacy/sysfs.h b/drivers/net/wireless/b43legacy/sysfs.h
new file mode 100644
index 00000000000..417d509803c
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.h
@@ -0,0 +1,9 @@
1#ifndef B43legacy_SYSFS_H_
2#define B43legacy_SYSFS_H_
3
4struct b43legacy_wldev;
5
6int b43legacy_sysfs_register(struct b43legacy_wldev *dev);
7void b43legacy_sysfs_unregister(struct b43legacy_wldev *dev);
8
9#endif /* B43legacy_SYSFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
new file mode 100644
index 00000000000..fa1e65687a6
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -0,0 +1,642 @@
1/*
2
3 Broadcom B43legacy wireless driver
4
5 Transmission (TX/RX) related functions.
6
7 Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
8 Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
9 Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
10 Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
11 Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
12 Copyright (C) 2007 Larry Finger <Larry.Finger@lwfinger.net>
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 <net/dst.h>
32
33#include "xmit.h"
34#include "phy.h"
35#include "dma.h"
36#include "pio.h"
37
38
39/* Extract the bitrate out of a CCK PLCP header. */
40static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp)
41{
42 switch (plcp->raw[0]) {
43 case 0x0A:
44 return B43legacy_CCK_RATE_1MB;
45 case 0x14:
46 return B43legacy_CCK_RATE_2MB;
47 case 0x37:
48 return B43legacy_CCK_RATE_5MB;
49 case 0x6E:
50 return B43legacy_CCK_RATE_11MB;
51 }
52 B43legacy_BUG_ON(1);
53 return 0;
54}
55
56/* Extract the bitrate out of an OFDM PLCP header. */
57static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp)
58{
59 switch (plcp->raw[0] & 0xF) {
60 case 0xB:
61 return B43legacy_OFDM_RATE_6MB;
62 case 0xF:
63 return B43legacy_OFDM_RATE_9MB;
64 case 0xA:
65 return B43legacy_OFDM_RATE_12MB;
66 case 0xE:
67 return B43legacy_OFDM_RATE_18MB;
68 case 0x9:
69 return B43legacy_OFDM_RATE_24MB;
70 case 0xD:
71 return B43legacy_OFDM_RATE_36MB;
72 case 0x8:
73 return B43legacy_OFDM_RATE_48MB;
74 case 0xC:
75 return B43legacy_OFDM_RATE_54MB;
76 }
77 B43legacy_BUG_ON(1);
78 return 0;
79}
80
81u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
82{
83 switch (bitrate) {
84 case B43legacy_CCK_RATE_1MB:
85 return 0x0A;
86 case B43legacy_CCK_RATE_2MB:
87 return 0x14;
88 case B43legacy_CCK_RATE_5MB:
89 return 0x37;
90 case B43legacy_CCK_RATE_11MB:
91 return 0x6E;
92 }
93 B43legacy_BUG_ON(1);
94 return 0;
95}
96
97u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate)
98{
99 switch (bitrate) {
100 case B43legacy_OFDM_RATE_6MB:
101 return 0xB;
102 case B43legacy_OFDM_RATE_9MB:
103 return 0xF;
104 case B43legacy_OFDM_RATE_12MB:
105 return 0xA;
106 case B43legacy_OFDM_RATE_18MB:
107 return 0xE;
108 case B43legacy_OFDM_RATE_24MB:
109 return 0x9;
110 case B43legacy_OFDM_RATE_36MB:
111 return 0xD;
112 case B43legacy_OFDM_RATE_48MB:
113 return 0x8;
114 case B43legacy_OFDM_RATE_54MB:
115 return 0xC;
116 }
117 B43legacy_BUG_ON(1);
118 return 0;
119}
120
121void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
122 const u16 octets, const u8 bitrate)
123{
124 __le32 *data = &(plcp->data);
125 __u8 *raw = plcp->raw;
126
127 if (b43legacy_is_ofdm_rate(bitrate)) {
128 u16 d;
129
130 d = b43legacy_plcp_get_ratecode_ofdm(bitrate);
131 B43legacy_WARN_ON(octets & 0xF000);
132 d |= (octets << 5);
133 *data = cpu_to_le32(d);
134 } else {
135 u32 plen;
136
137 plen = octets * 16 / bitrate;
138 if ((octets * 16 % bitrate) > 0) {
139 plen++;
140 if ((bitrate == B43legacy_CCK_RATE_11MB)
141 && ((octets * 8 % 11) < 4))
142 raw[1] = 0x84;
143 else
144 raw[1] = 0x04;
145 } else
146 raw[1] = 0x04;
147 *data |= cpu_to_le32(plen << 16);
148 raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate);
149 }
150}
151
152static u8 b43legacy_calc_fallback_rate(u8 bitrate)
153{
154 switch (bitrate) {
155 case B43legacy_CCK_RATE_1MB:
156 return B43legacy_CCK_RATE_1MB;
157 case B43legacy_CCK_RATE_2MB:
158 return B43legacy_CCK_RATE_1MB;
159 case B43legacy_CCK_RATE_5MB:
160 return B43legacy_CCK_RATE_2MB;
161 case B43legacy_CCK_RATE_11MB:
162 return B43legacy_CCK_RATE_5MB;
163 case B43legacy_OFDM_RATE_6MB:
164 return B43legacy_CCK_RATE_5MB;
165 case B43legacy_OFDM_RATE_9MB:
166 return B43legacy_OFDM_RATE_6MB;
167 case B43legacy_OFDM_RATE_12MB:
168 return B43legacy_OFDM_RATE_9MB;
169 case B43legacy_OFDM_RATE_18MB:
170 return B43legacy_OFDM_RATE_12MB;
171 case B43legacy_OFDM_RATE_24MB:
172 return B43legacy_OFDM_RATE_18MB;
173 case B43legacy_OFDM_RATE_36MB:
174 return B43legacy_OFDM_RATE_24MB;
175 case B43legacy_OFDM_RATE_48MB:
176 return B43legacy_OFDM_RATE_36MB;
177 case B43legacy_OFDM_RATE_54MB:
178 return B43legacy_OFDM_RATE_48MB;
179 }
180 B43legacy_BUG_ON(1);
181 return 0;
182}
183
184static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
185 struct b43legacy_txhdr_fw3 *txhdr,
186 const unsigned char *fragment_data,
187 unsigned int fragment_len,
188 const struct ieee80211_tx_control *txctl,
189 u16 cookie)
190{
191 const struct ieee80211_hdr *wlhdr;
192 int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
193 u16 fctl;
194 u8 rate;
195 u8 rate_fb;
196 int rate_ofdm;
197 int rate_fb_ofdm;
198 unsigned int plcp_fragment_len;
199 u32 mac_ctl = 0;
200 u16 phy_ctl = 0;
201
202 wlhdr = (const struct ieee80211_hdr *)fragment_data;
203 fctl = le16_to_cpu(wlhdr->frame_control);
204
205 memset(txhdr, 0, sizeof(*txhdr));
206
207 rate = txctl->tx_rate;
208 rate_ofdm = b43legacy_is_ofdm_rate(rate);
209 rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
210 rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb);
211
212 txhdr->mac_frame_ctl = wlhdr->frame_control;
213 memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
214
215 /* Calculate duration for fallback rate */
216 if ((rate_fb == rate) ||
217 (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
218 (wlhdr->duration_id == cpu_to_le16(0))) {
219 /* If the fallback rate equals the normal rate or the
220 * dur_id field contains an AID, CFP magic or 0,
221 * use the original dur_id field. */
222 txhdr->dur_fb = wlhdr->duration_id;
223 } else {
224 int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
225 txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
226 dev->wl->if_id,
227 fragment_len,
228 fbrate_base100kbps);
229 }
230
231 plcp_fragment_len = fragment_len + FCS_LEN;
232 if (use_encryption) {
233 u8 key_idx = (u16)(txctl->key_idx);
234 struct b43legacy_key *key;
235 int wlhdr_len;
236 size_t iv_len;
237
238 B43legacy_WARN_ON(key_idx >= dev->max_nr_keys);
239 key = &(dev->key[key_idx]);
240
241 if (key->enabled) {
242 /* Hardware appends ICV. */
243 plcp_fragment_len += txctl->icv_len;
244
245 key_idx = b43legacy_kidx_to_fw(dev, key_idx);
246 mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
247 B43legacy_TX4_MAC_KEYIDX;
248 mac_ctl |= (key->algorithm <<
249 B43legacy_TX4_MAC_KEYALG_SHIFT) &
250 B43legacy_TX4_MAC_KEYALG;
251 wlhdr_len = ieee80211_get_hdrlen(fctl);
252 iv_len = min((size_t)txctl->iv_len,
253 ARRAY_SIZE(txhdr->iv));
254 memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
255 }
256 }
257 b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
258 (&txhdr->plcp), plcp_fragment_len,
259 rate);
260 b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
261 (&txhdr->plcp_fb), plcp_fragment_len,
262 rate_fb);
263
264 /* PHY TX Control word */
265 if (rate_ofdm)
266 phy_ctl |= B43legacy_TX4_PHY_OFDM;
267 if (dev->short_preamble)
268 phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
269 switch (txctl->antenna_sel_tx) {
270 case 0:
271 phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
272 break;
273 case 1:
274 phy_ctl |= B43legacy_TX4_PHY_ANT0;
275 break;
276 case 2:
277 phy_ctl |= B43legacy_TX4_PHY_ANT1;
278 break;
279 default:
280 B43legacy_BUG_ON(1);
281 }
282
283 /* MAC control */
284 if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
285 mac_ctl |= B43legacy_TX4_MAC_ACK;
286 if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
287 ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
288 mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
289 if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
290 mac_ctl |= B43legacy_TX4_MAC_STMSDU;
291 if (rate_fb_ofdm)
292 mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
293
294 /* Generate the RTS or CTS-to-self frame */
295 if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
296 (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
297 unsigned int len;
298 struct ieee80211_hdr *hdr;
299 int rts_rate;
300 int rts_rate_fb;
301 int rts_rate_ofdm;
302 int rts_rate_fb_ofdm;
303
304 rts_rate = txctl->rts_cts_rate;
305 rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
306 rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
307 rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
308 if (rts_rate_fb_ofdm)
309 mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
310
311 if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
312 ieee80211_ctstoself_get(dev->wl->hw,
313 dev->wl->if_id,
314 fragment_data,
315 fragment_len, txctl,
316 (struct ieee80211_cts *)
317 (txhdr->rts_frame));
318 mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
319 len = sizeof(struct ieee80211_cts);
320 } else {
321 ieee80211_rts_get(dev->wl->hw,
322 dev->wl->if_id,
323 fragment_data, fragment_len, txctl,
324 (struct ieee80211_rts *)
325 (txhdr->rts_frame));
326 mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
327 len = sizeof(struct ieee80211_rts);
328 }
329 len += FCS_LEN;
330 b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
331 (&txhdr->rts_plcp),
332 len, rts_rate);
333 b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
334 (&txhdr->rts_plcp_fb),
335 len, rts_rate_fb);
336 hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
337 txhdr->rts_dur_fb = hdr->duration_id;
338 mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
339 }
340
341 /* Magic cookie */
342 txhdr->cookie = cpu_to_le16(cookie);
343
344 /* Apply the bitfields */
345 txhdr->mac_ctl = cpu_to_le32(mac_ctl);
346 txhdr->phy_ctl = cpu_to_le16(phy_ctl);
347}
348
349void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
350 u8 *txhdr,
351 const unsigned char *fragment_data,
352 unsigned int fragment_len,
353 const struct ieee80211_tx_control *txctl,
354 u16 cookie)
355{
356 generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
357 fragment_data, fragment_len,
358 txctl, cookie);
359}
360
361static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
362 u8 in_rssi, int ofdm,
363 int adjust_2053, int adjust_2050)
364{
365 struct b43legacy_phy *phy = &dev->phy;
366 s32 tmp;
367
368 switch (phy->radio_ver) {
369 case 0x2050:
370 if (ofdm) {
371 tmp = in_rssi;
372 if (tmp > 127)
373 tmp -= 256;
374 tmp *= 73;
375 tmp /= 64;
376 if (adjust_2050)
377 tmp += 25;
378 else
379 tmp -= 3;
380 } else {
381 if (dev->dev->bus->sprom.r1.boardflags_lo
382 & B43legacy_BFL_RSSI) {
383 if (in_rssi > 63)
384 in_rssi = 63;
385 tmp = phy->nrssi_lt[in_rssi];
386 tmp = 31 - tmp;
387 tmp *= -131;
388 tmp /= 128;
389 tmp -= 57;
390 } else {
391 tmp = in_rssi;
392 tmp = 31 - tmp;
393 tmp *= -149;
394 tmp /= 128;
395 tmp -= 68;
396 }
397 if (phy->type == B43legacy_PHYTYPE_G &&
398 adjust_2050)
399 tmp += 25;
400 }
401 break;
402 case 0x2060:
403 if (in_rssi > 127)
404 tmp = in_rssi - 256;
405 else
406 tmp = in_rssi;
407 break;
408 default:
409 tmp = in_rssi;
410 tmp -= 11;
411 tmp *= 103;
412 tmp /= 64;
413 if (adjust_2053)
414 tmp -= 109;
415 else
416 tmp -= 83;
417 }
418
419 return (s8)tmp;
420}
421
422void b43legacy_rx(struct b43legacy_wldev *dev,
423 struct sk_buff *skb,
424 const void *_rxhdr)
425{
426 struct ieee80211_rx_status status;
427 struct b43legacy_plcp_hdr6 *plcp;
428 struct ieee80211_hdr *wlhdr;
429 const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
430 u16 fctl;
431 u16 phystat0;
432 u16 phystat3;
433 u16 chanstat;
434 u16 mactime;
435 u32 macstat;
436 u16 chanid;
437 u8 jssi;
438 int padding;
439
440 memset(&status, 0, sizeof(status));
441
442 /* Get metadata about the frame from the header. */
443 phystat0 = le16_to_cpu(rxhdr->phy_status0);
444 phystat3 = le16_to_cpu(rxhdr->phy_status3);
445 jssi = rxhdr->jssi;
446 macstat = le16_to_cpu(rxhdr->mac_status);
447 mactime = le16_to_cpu(rxhdr->mac_time);
448 chanstat = le16_to_cpu(rxhdr->channel);
449
450 if (macstat & B43legacy_RX_MAC_FCSERR)
451 dev->wl->ieee_stats.dot11FCSErrorCount++;
452
453 /* Skip PLCP and padding */
454 padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0;
455 if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) +
456 padding))) {
457 b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n");
458 goto drop;
459 }
460 plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding);
461 skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding);
462 /* The skb contains the Wireless Header + payload data now */
463 if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) {
464 b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n");
465 goto drop;
466 }
467 wlhdr = (struct ieee80211_hdr *)(skb->data);
468 fctl = le16_to_cpu(wlhdr->frame_control);
469
470 if ((macstat & B43legacy_RX_MAC_DEC) &&
471 !(macstat & B43legacy_RX_MAC_DECERR)) {
472 unsigned int keyidx;
473 int wlhdr_len;
474 int iv_len;
475 int icv_len;
476
477 keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX)
478 >> B43legacy_RX_MAC_KEYIDX_SHIFT);
479 /* We must adjust the key index here. We want the "physical"
480 * key index, but the ucode passed it slightly different.
481 */
482 keyidx = b43legacy_kidx_to_raw(dev, keyidx);
483 B43legacy_WARN_ON(keyidx >= dev->max_nr_keys);
484
485 if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
486 /* Remove PROTECTED flag to mark it as decrypted. */
487 B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED));
488 fctl &= ~IEEE80211_FCTL_PROTECTED;
489 wlhdr->frame_control = cpu_to_le16(fctl);
490
491 wlhdr_len = ieee80211_get_hdrlen(fctl);
492 if (unlikely(skb->len < (wlhdr_len + 3))) {
493 b43legacydbg(dev->wl, "RX: Packet size"
494 " underrun3\n");
495 goto drop;
496 }
497 if (skb->data[wlhdr_len + 3] & (1 << 5)) {
498 /* The Ext-IV Bit is set in the "KeyID"
499 * octet of the IV.
500 */
501 iv_len = 8;
502 icv_len = 8;
503 } else {
504 iv_len = 4;
505 icv_len = 4;
506 }
507 if (unlikely(skb->len < (wlhdr_len + iv_len +
508 icv_len))) {
509 b43legacydbg(dev->wl, "RX: Packet size"
510 " underrun4\n");
511 goto drop;
512 }
513 /* Remove the IV */
514 memmove(skb->data + iv_len, skb->data, wlhdr_len);
515 skb_pull(skb, iv_len);
516 /* Remove the ICV */
517 skb_trim(skb, skb->len - icv_len);
518
519 status.flag |= RX_FLAG_DECRYPTED;
520 }
521 }
522
523 status.ssi = b43legacy_rssi_postprocess(dev, jssi,
524 (phystat0 & B43legacy_RX_PHYST0_OFDM),
525 (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
526 (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
527 status.noise = dev->stats.link_noise;
528 status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
529 if (phystat0 & B43legacy_RX_PHYST0_OFDM)
530 status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp);
531 else
532 status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
533 status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
534 status.mactime = mactime;
535
536 chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
537 B43legacy_RX_CHAN_ID_SHIFT;
538 switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
539 case B43legacy_PHYTYPE_B:
540 status.phymode = MODE_IEEE80211B;
541 status.freq = chanid + 2400;
542 status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
543 break;
544 case B43legacy_PHYTYPE_G:
545 status.phymode = MODE_IEEE80211G;
546 status.freq = chanid + 2400;
547 status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
548 break;
549 default:
550 b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
551 chanstat);
552 }
553
554 dev->stats.last_rx = jiffies;
555 ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
556
557 return;
558drop:
559 b43legacydbg(dev->wl, "RX: Packet dropped\n");
560 dev_kfree_skb_any(skb);
561}
562
563void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
564 const struct b43legacy_txstatus *status)
565{
566 b43legacy_debugfs_log_txstat(dev, status);
567
568 if (status->intermediate)
569 return;
570 if (status->for_ampdu)
571 return;
572 if (!status->acked)
573 dev->wl->ieee_stats.dot11ACKFailureCount++;
574 if (status->rts_count) {
575 if (status->rts_count == 0xF) /* FIXME */
576 dev->wl->ieee_stats.dot11RTSFailureCount++;
577 else
578 dev->wl->ieee_stats.dot11RTSSuccessCount++;
579 }
580
581 if (b43legacy_using_pio(dev))
582 b43legacy_pio_handle_txstatus(dev, status);
583 else
584 b43legacy_dma_handle_txstatus(dev, status);
585}
586
587/* Handle TX status report as received through DMA/PIO queues */
588void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
589 const struct b43legacy_hwtxstatus *hw)
590{
591 struct b43legacy_txstatus status;
592 u8 tmp;
593
594 status.cookie = le16_to_cpu(hw->cookie);
595 status.seq = le16_to_cpu(hw->seq);
596 status.phy_stat = hw->phy_stat;
597 tmp = hw->count;
598 status.frame_count = (tmp >> 4);
599 status.rts_count = (tmp & 0x0F);
600 tmp = hw->flags;
601 status.supp_reason = ((tmp & 0x1C) >> 2);
602 status.pm_indicated = !!(tmp & 0x80);
603 status.intermediate = !!(tmp & 0x40);
604 status.for_ampdu = !!(tmp & 0x20);
605 status.acked = !!(tmp & 0x02);
606
607 b43legacy_handle_txstatus(dev, &status);
608}
609
610/* Stop any TX operation on the device (suspend the hardware queues) */
611void b43legacy_tx_suspend(struct b43legacy_wldev *dev)
612{
613 if (b43legacy_using_pio(dev))
614 b43legacy_pio_freeze_txqueues(dev);
615 else
616 b43legacy_dma_tx_suspend(dev);
617}
618
619/* Resume any TX operation on the device (resume the hardware queues) */
620void b43legacy_tx_resume(struct b43legacy_wldev *dev)
621{
622 if (b43legacy_using_pio(dev))
623 b43legacy_pio_thaw_txqueues(dev);
624 else
625 b43legacy_dma_tx_resume(dev);
626}
627
628/* Initialize the QoS parameters */
629void b43legacy_qos_init(struct b43legacy_wldev *dev)
630{
631 /* FIXME: This function must probably be called from the mac80211
632 * config callback. */
633return;
634
635 b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF);
636 /* FIXME kill magic */
637 b43legacy_write16(dev, 0x688,
638 b43legacy_read16(dev, 0x688) | 0x4);
639
640
641 /*TODO: We might need some stack support here to get the values. */
642}
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
new file mode 100644
index 00000000000..8a155d0a5d1
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -0,0 +1,259 @@
1#ifndef B43legacy_XMIT_H_
2#define B43legacy_XMIT_H_
3
4#include "main.h"
5
6
7#define _b43legacy_declare_plcp_hdr(size) \
8 struct b43legacy_plcp_hdr##size { \
9 union { \
10 __le32 data; \
11 __u8 raw[size]; \
12 } __attribute__((__packed__)); \
13 } __attribute__((__packed__))
14
15/* struct b43legacy_plcp_hdr4 */
16_b43legacy_declare_plcp_hdr(4);
17/* struct b43legacy_plcp_hdr6 */
18_b43legacy_declare_plcp_hdr(6);
19
20#undef _b43legacy_declare_plcp_hdr
21
22
23/* TX header for v3 firmware */
24struct b43legacy_txhdr_fw3 {
25 __le32 mac_ctl; /* MAC TX control */
26 __le16 mac_frame_ctl; /* Copy of the FrameControl */
27 __le16 tx_fes_time_norm; /* TX FES Time Normal */
28 __le16 phy_ctl; /* PHY TX control */
29 __u8 iv[16]; /* Encryption IV */
30 __u8 tx_receiver[6]; /* TX Frame Receiver address */
31 __le16 tx_fes_time_fb; /* TX FES Time Fallback */
32 struct b43legacy_plcp_hdr4 rts_plcp_fb; /* RTS fallback PLCP */
33 __le16 rts_dur_fb; /* RTS fallback duration */
34 struct b43legacy_plcp_hdr4 plcp_fb; /* Fallback PLCP */
35 __le16 dur_fb; /* Fallback duration */
36 PAD_BYTES(2);
37 __le16 cookie;
38 __le16 unknown_scb_stuff;
39 struct b43legacy_plcp_hdr6 rts_plcp; /* RTS PLCP */
40 __u8 rts_frame[18]; /* The RTS frame (if used) */
41 struct b43legacy_plcp_hdr6 plcp;
42} __attribute__((__packed__));
43
44/* MAC TX control */
45#define B43legacy_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
46#define B43legacy_TX4_MAC_KEYIDX_SHIFT 20
47#define B43legacy_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
48#define B43legacy_TX4_MAC_KEYALG_SHIFT 16
49#define B43legacy_TX4_MAC_LIFETIME 0x00001000
50#define B43legacy_TX4_MAC_FRAMEBURST 0x00000800
51#define B43legacy_TX4_MAC_SENDCTS 0x00000400
52#define B43legacy_TX4_MAC_AMPDU 0x00000300
53#define B43legacy_TX4_MAC_AMPDU_SHIFT 8
54#define B43legacy_TX4_MAC_CTSFALLBACKOFDM 0x00000200
55#define B43legacy_TX4_MAC_FALLBACKOFDM 0x00000100
56#define B43legacy_TX4_MAC_5GHZ 0x00000080
57#define B43legacy_TX4_MAC_IGNPMQ 0x00000020
58#define B43legacy_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Seq No */
59#define B43legacy_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
60#define B43legacy_TX4_MAC_SENDRTS 0x00000004
61#define B43legacy_TX4_MAC_LONGFRAME 0x00000002
62#define B43legacy_TX4_MAC_ACK 0x00000001
63
64/* Extra Frame Types */
65#define B43legacy_TX4_EFT_FBOFDM 0x0001 /* Data frame fb rate type */
66#define B43legacy_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
67#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
68
69/* PHY TX control word */
70#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
71#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
72#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */
73#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
74#define B43legacy_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
75#define B43legacy_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
76
77
78
79void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
80 u8 *txhdr,
81 const unsigned char *fragment_data,
82 unsigned int fragment_len,
83 const struct ieee80211_tx_control *txctl,
84 u16 cookie);
85
86
87/* Transmit Status */
88struct b43legacy_txstatus {
89 u16 cookie; /* The cookie from the txhdr */
90 u16 seq; /* Sequence number */
91 u8 phy_stat; /* PHY TX status */
92 u8 frame_count; /* Frame transmit count */
93 u8 rts_count; /* RTS transmit count */
94 u8 supp_reason; /* Suppression reason */
95 /* flags */
96 u8 pm_indicated;/* PM mode indicated to AP */
97 u8 intermediate;/* Intermediate status notification */
98 u8 for_ampdu; /* Status is for an AMPDU (afterburner) */
99 u8 acked; /* Wireless ACK received */
100};
101
102/* txstatus supp_reason values */
103enum {
104 B43legacy_TXST_SUPP_NONE, /* Not suppressed */
105 B43legacy_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */
106 B43legacy_TXST_SUPP_FLUSH, /* Suppressed due to flush request */
107 B43legacy_TXST_SUPP_PREV, /* Previous fragment failed */
108 B43legacy_TXST_SUPP_CHAN, /* Channel mismatch */
109 B43legacy_TXST_SUPP_LIFE, /* Lifetime expired */
110 B43legacy_TXST_SUPP_UNDER, /* Buffer underflow */
111 B43legacy_TXST_SUPP_ABNACK, /* Afterburner NACK */
112};
113
114/* Transmit Status as received through DMA/PIO on old chips */
115struct b43legacy_hwtxstatus {
116 PAD_BYTES(4);
117 __le16 cookie;
118 u8 flags;
119 u8 count;
120 PAD_BYTES(2);
121 __le16 seq;
122 u8 phy_stat;
123 PAD_BYTES(1);
124} __attribute__((__packed__));
125
126
127/* Receive header for v3 firmware. */
128struct b43legacy_rxhdr_fw3 {
129 __le16 frame_len; /* Frame length */
130 PAD_BYTES(2);
131 __le16 phy_status0; /* PHY RX Status 0 */
132 __u8 jssi; /* PHY RX Status 1: JSSI */
133 __u8 sig_qual; /* PHY RX Status 1: Signal Quality */
134 PAD_BYTES(2); /* PHY RX Status 2 */
135 __le16 phy_status3; /* PHY RX Status 3 */
136 __le16 mac_status; /* MAC RX status */
137 __le16 mac_time;
138 __le16 channel;
139} __attribute__((__packed__));
140
141
142/* PHY RX Status 0 */
143#define B43legacy_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
144#define B43legacy_RX_PHYST0_PLCPHCF 0x0200
145#define B43legacy_RX_PHYST0_PLCPFV 0x0100
146#define B43legacy_RX_PHYST0_SHORTPRMBL 0x0080 /* Recvd with Short Preamble */
147#define B43legacy_RX_PHYST0_LCRS 0x0040
148#define B43legacy_RX_PHYST0_ANT 0x0020 /* Antenna */
149#define B43legacy_RX_PHYST0_UNSRATE 0x0010
150#define B43legacy_RX_PHYST0_CLIP 0x000C
151#define B43legacy_RX_PHYST0_CLIP_SHIFT 2
152#define B43legacy_RX_PHYST0_FTYPE 0x0003 /* Frame type */
153#define B43legacy_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
154#define B43legacy_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
155#define B43legacy_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
156#define B43legacy_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
157
158/* PHY RX Status 2 */
159#define B43legacy_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
160#define B43legacy_RX_PHYST2_LNAG_SHIFT 14
161#define B43legacy_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
162#define B43legacy_RX_PHYST2_PNAG_SHIFT 10
163#define B43legacy_RX_PHYST2_FOFF 0x03FF /* F offset */
164
165/* PHY RX Status 3 */
166#define B43legacy_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
167#define B43legacy_RX_PHYST3_DIGG_SHIFT 11
168#define B43legacy_RX_PHYST3_TRSTATE 0x0400 /* TR state */
169
170/* MAC RX Status */
171#define B43legacy_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
172#define B43legacy_RX_MAC_KEYIDX 0x000007E0 /* Key index */
173#define B43legacy_RX_MAC_KEYIDX_SHIFT 5
174#define B43legacy_RX_MAC_DECERR 0x00000010 /* Decrypt error */
175#define B43legacy_RX_MAC_DEC 0x00000008 /* Decryption attempted */
176#define B43legacy_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
177#define B43legacy_RX_MAC_RESP 0x00000002 /* Response frame xmitted */
178#define B43legacy_RX_MAC_FCSERR 0x00000001 /* FCS error */
179
180/* RX channel */
181#define B43legacy_RX_CHAN_GAIN 0xFC00 /* Gain */
182#define B43legacy_RX_CHAN_GAIN_SHIFT 10
183#define B43legacy_RX_CHAN_ID 0x03FC /* Channel ID */
184#define B43legacy_RX_CHAN_ID_SHIFT 2
185#define B43legacy_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
186
187
188
189u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate);
190u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate);
191
192void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
193 const u16 octets, const u8 bitrate);
194
195void b43legacy_rx(struct b43legacy_wldev *dev,
196 struct sk_buff *skb,
197 const void *_rxhdr);
198
199void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
200 const struct b43legacy_txstatus *status);
201
202void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
203 const struct b43legacy_hwtxstatus *hw);
204
205void b43legacy_tx_suspend(struct b43legacy_wldev *dev);
206void b43legacy_tx_resume(struct b43legacy_wldev *dev);
207
208
209#define B43legacy_NR_QOSPARMS 22
210enum {
211 B43legacy_QOSPARM_TXOP = 0,
212 B43legacy_QOSPARM_CWMIN,
213 B43legacy_QOSPARM_CWMAX,
214 B43legacy_QOSPARM_CWCUR,
215 B43legacy_QOSPARM_AIFS,
216 B43legacy_QOSPARM_BSLOTS,
217 B43legacy_QOSPARM_REGGAP,
218 B43legacy_QOSPARM_STATUS,
219};
220
221void b43legacy_qos_init(struct b43legacy_wldev *dev);
222
223
224/* Helper functions for converting the key-table index from "firmware-format"
225 * to "raw-format" and back. The firmware API changed for this at some revision.
226 * We need to account for that here. */
227static inline
228int b43legacy_new_kidx_api(struct b43legacy_wldev *dev)
229{
230 /* FIXME: Not sure the change was at rev 351 */
231 return (dev->fw.rev >= 351);
232}
233static inline
234u8 b43legacy_kidx_to_fw(struct b43legacy_wldev *dev, u8 raw_kidx)
235{
236 u8 firmware_kidx;
237 if (b43legacy_new_kidx_api(dev))
238 firmware_kidx = raw_kidx;
239 else {
240 if (raw_kidx >= 4) /* Is per STA key? */
241 firmware_kidx = raw_kidx - 4;
242 else
243 firmware_kidx = raw_kidx; /* TX default key */
244 }
245 return firmware_kidx;
246}
247static inline
248u8 b43legacy_kidx_to_raw(struct b43legacy_wldev *dev, u8 firmware_kidx)
249{
250 u8 raw_kidx;
251 if (b43legacy_new_kidx_api(dev))
252 raw_kidx = firmware_kidx;
253 else
254 /* RX default keys or per STA keys */
255 raw_kidx = firmware_kidx + 4;
256 return raw_kidx;
257}
258
259#endif /* B43legacy_XMIT_H_ */