Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6

+15605 -22
+36
Documentation/networking/bcm43xx.txt
··· 1 + 2 + BCM43xx Linux Driver Project 3 + ============================ 4 + 5 + About this software 6 + ------------------- 7 + 8 + The goal of this project is to develop a linux driver for Broadcom 9 + BCM43xx chips, based on the specification at 10 + http://bcm-specs.sipsolutions.net/ 11 + 12 + The project page is http://bcm43xx.berlios.de/ 13 + 14 + 15 + Requirements 16 + ------------ 17 + 18 + 1) Linux Kernel 2.6.16 or later 19 + http://www.kernel.org/ 20 + 21 + You may want to configure your kernel with: 22 + 23 + CONFIG_DEBUG_FS (optional): 24 + -> Kernel hacking 25 + -> Debug Filesystem 26 + 27 + 2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 28 + modules: 29 + http://softmac.sipsolutions.net/ 30 + 31 + 3) Firmware Files 32 + 33 + Please try fwcutter. Fwcutter can extract the firmware from various 34 + binary driver files. It supports driver files from Windows, MacOS and 35 + Linux. You can get fwcutter from http://bcm43xx.berlios.de/. 36 + Also, fwcutter comes with a README file for further instructions.
+6 -1
drivers/net/wireless/Kconfig
··· 309 309 Say Y here to support the Airport 802.11b wireless Ethernet hardware 310 310 built into the Macintosh iBook and other recent PowerPC-based 311 311 Macintosh machines. This is essentially a Lucent Orinoco card with 312 - a non-standard interface 312 + a non-standard interface. 313 + 314 + This driver does not support the Airport Extreme (802.11b/g). Use 315 + the BCM43xx driver for Airport Extreme cards. 313 316 314 317 config PLX_HERMES 315 318 tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" ··· 404 401 config PCMCIA_SPECTRUM 405 402 tristate "Symbol Spectrum24 Trilogy PCMCIA card support" 406 403 depends on NET_RADIO && PCMCIA && HERMES 404 + select FW_LOADER 407 405 ---help--- 408 406 409 407 This is a driver for 802.11b cards using RAM-loadable Symbol ··· 504 500 will be called prism54.ko. 505 501 506 502 source "drivers/net/wireless/hostap/Kconfig" 503 + source "drivers/net/wireless/bcm43xx/Kconfig" 507 504 508 505 # yes, this works even when no drivers are selected 509 506 config NET_WIRELESS
+1
drivers/net/wireless/Makefile
··· 35 35 obj-$(CONFIG_PRISM54) += prism54/ 36 36 37 37 obj-$(CONFIG_HOSTAP) += hostap/ 38 + obj-$(CONFIG_BCM43XX) += bcm43xx/ 38 39 39 40 # 16-bit wireless PCMCIA client drivers 40 41 obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
+62
drivers/net/wireless/bcm43xx/Kconfig
··· 1 + config BCM43XX 2 + tristate "Broadcom BCM43xx wireless support" 3 + depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL 4 + select FW_LOADER 5 + ---help--- 6 + This is an experimental driver for the Broadcom 43xx wireless chip, 7 + found in the Apple Airport Extreme and various other devices. 8 + 9 + config BCM43XX_DEBUG 10 + bool "Broadcom BCM43xx debugging (RECOMMENDED)" 11 + depends on BCM43XX 12 + default y 13 + ---help--- 14 + Broadcom 43xx debugging messages. 15 + Say Y, because the driver is still very experimental and 16 + this will help you get it running. 17 + 18 + config BCM43XX_DMA 19 + bool 20 + config BCM43XX_PIO 21 + bool 22 + 23 + choice 24 + prompt "BCM43xx data transfer mode" 25 + depends on BCM43XX 26 + default BCM43XX_DMA_AND_PIO_MODE 27 + 28 + config BCM43XX_DMA_AND_PIO_MODE 29 + bool "DMA + PIO" 30 + select BCM43XX_DMA 31 + select BCM43XX_PIO 32 + ---help--- 33 + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) 34 + data transfer modes. 35 + The actually used mode is selectable through the module 36 + parameter "pio". If the module parameter is pio=0, DMA is used. 37 + Otherwise PIO is used. DMA is default. 38 + 39 + If unsure, choose this option. 40 + 41 + config BCM43XX_DMA_MODE 42 + bool "DMA (Direct Memory Access) only" 43 + select BCM43XX_DMA 44 + ---help--- 45 + Only include Direct Memory Access (DMA). 46 + This reduces the size of the driver module, by omitting the PIO code. 47 + 48 + config BCM43XX_PIO_MODE 49 + bool "PIO (Programmed I/O) only" 50 + select BCM43XX_PIO 51 + ---help--- 52 + Only include Programmed I/O (PIO). 53 + This reduces the size of the driver module, by omitting the DMA code. 54 + Please note that PIO transfers are slow (compared to DMA). 55 + 56 + Also note that not all devices of the 43xx series support PIO. 57 + The 4306 (Apple Airport Extreme and others) supports PIO, while 58 + the 4318 is known to _not_ support PIO. 59 + 60 + Only use PIO, if DMA does not work for you. 61 + 62 + endchoice
+12
drivers/net/wireless/bcm43xx/Makefile
··· 1 + obj-$(CONFIG_BCM43XX) += bcm43xx.o 2 + bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o 3 + 4 + bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o 5 + bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o 6 + 7 + bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ 8 + bcm43xx_radio.o bcm43xx_phy.o \ 9 + bcm43xx_power.o bcm43xx_wx.o \ 10 + bcm43xx_leds.o bcm43xx_ethtool.o \ 11 + bcm43xx_xmit.o bcm43xx_sysfs.o \ 12 + $(bcm43xx-obj-y)
+926
drivers/net/wireless/bcm43xx/bcm43xx.h
··· 1 + #ifndef BCM43xx_H_ 2 + #define BCM43xx_H_ 3 + 4 + #include <linux/version.h> 5 + #include <linux/kernel.h> 6 + #include <linux/spinlock.h> 7 + #include <linux/interrupt.h> 8 + #include <linux/stringify.h> 9 + #include <linux/pci.h> 10 + #include <net/ieee80211.h> 11 + #include <net/ieee80211softmac.h> 12 + #include <asm/atomic.h> 13 + #include <asm/io.h> 14 + 15 + 16 + #include "bcm43xx_debugfs.h" 17 + #include "bcm43xx_leds.h" 18 + #include "bcm43xx_sysfs.h" 19 + 20 + 21 + #define PFX KBUILD_MODNAME ": " 22 + 23 + #define BCM43xx_SWITCH_CORE_MAX_RETRIES 50 24 + #define BCM43xx_IRQWAIT_MAX_RETRIES 50 25 + 26 + #define BCM43xx_IO_SIZE 8192 27 + 28 + /* Active Core PCI Configuration Register. */ 29 + #define BCM43xx_PCICFG_ACTIVE_CORE 0x80 30 + /* SPROM control register. */ 31 + #define BCM43xx_PCICFG_SPROMCTL 0x88 32 + /* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ 33 + #define BCM43xx_PCICFG_ICR 0x94 34 + 35 + /* MMIO offsets */ 36 + #define BCM43xx_MMIO_DMA1_REASON 0x20 37 + #define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24 38 + #define BCM43xx_MMIO_DMA2_REASON 0x28 39 + #define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C 40 + #define BCM43xx_MMIO_DMA3_REASON 0x30 41 + #define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34 42 + #define BCM43xx_MMIO_DMA4_REASON 0x38 43 + #define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C 44 + #define BCM43xx_MMIO_STATUS_BITFIELD 0x120 45 + #define BCM43xx_MMIO_STATUS2_BITFIELD 0x124 46 + #define BCM43xx_MMIO_GEN_IRQ_REASON 0x128 47 + #define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C 48 + #define BCM43xx_MMIO_RAM_CONTROL 0x130 49 + #define BCM43xx_MMIO_RAM_DATA 0x134 50 + #define BCM43xx_MMIO_PS_STATUS 0x140 51 + #define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158 52 + #define BCM43xx_MMIO_SHM_CONTROL 0x160 53 + #define BCM43xx_MMIO_SHM_DATA 0x164 54 + #define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166 55 + #define BCM43xx_MMIO_XMITSTAT_0 0x170 56 + #define BCM43xx_MMIO_XMITSTAT_1 0x174 57 + #define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ 58 + #define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ 59 + #define BCM43xx_MMIO_DMA1_BASE 0x200 60 + #define BCM43xx_MMIO_DMA2_BASE 0x220 61 + #define BCM43xx_MMIO_DMA3_BASE 0x240 62 + #define BCM43xx_MMIO_DMA4_BASE 0x260 63 + #define BCM43xx_MMIO_PIO1_BASE 0x300 64 + #define BCM43xx_MMIO_PIO2_BASE 0x310 65 + #define BCM43xx_MMIO_PIO3_BASE 0x320 66 + #define BCM43xx_MMIO_PIO4_BASE 0x330 67 + #define BCM43xx_MMIO_PHY_VER 0x3E0 68 + #define BCM43xx_MMIO_PHY_RADIO 0x3E2 69 + #define BCM43xx_MMIO_ANTENNA 0x3E8 70 + #define BCM43xx_MMIO_CHANNEL 0x3F0 71 + #define BCM43xx_MMIO_CHANNEL_EXT 0x3F4 72 + #define BCM43xx_MMIO_RADIO_CONTROL 0x3F6 73 + #define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8 74 + #define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA 75 + #define BCM43xx_MMIO_PHY_CONTROL 0x3FC 76 + #define BCM43xx_MMIO_PHY_DATA 0x3FE 77 + #define BCM43xx_MMIO_MACFILTER_CONTROL 0x420 78 + #define BCM43xx_MMIO_MACFILTER_DATA 0x422 79 + #define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A 80 + #define BCM43xx_MMIO_GPIO_CONTROL 0x49C 81 + #define BCM43xx_MMIO_GPIO_MASK 0x49E 82 + #define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */ 83 + #define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ 84 + #define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ 85 + #define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ 86 + #define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 87 + 88 + /* SPROM offsets. */ 89 + #define BCM43xx_SPROM_BASE 0x1000 90 + #define BCM43xx_SPROM_BOARDFLAGS2 0x1c 91 + #define BCM43xx_SPROM_IL0MACADDR 0x24 92 + #define BCM43xx_SPROM_ET0MACADDR 0x27 93 + #define BCM43xx_SPROM_ET1MACADDR 0x2a 94 + #define BCM43xx_SPROM_ETHPHY 0x2d 95 + #define BCM43xx_SPROM_BOARDREV 0x2e 96 + #define BCM43xx_SPROM_PA0B0 0x2f 97 + #define BCM43xx_SPROM_PA0B1 0x30 98 + #define BCM43xx_SPROM_PA0B2 0x31 99 + #define BCM43xx_SPROM_WL0GPIO0 0x32 100 + #define BCM43xx_SPROM_WL0GPIO2 0x33 101 + #define BCM43xx_SPROM_MAXPWR 0x34 102 + #define BCM43xx_SPROM_PA1B0 0x35 103 + #define BCM43xx_SPROM_PA1B1 0x36 104 + #define BCM43xx_SPROM_PA1B2 0x37 105 + #define BCM43xx_SPROM_IDL_TSSI_TGT 0x38 106 + #define BCM43xx_SPROM_BOARDFLAGS 0x39 107 + #define BCM43xx_SPROM_ANTENNA_GAIN 0x3a 108 + #define BCM43xx_SPROM_VERSION 0x3f 109 + 110 + /* BCM43xx_SPROM_BOARDFLAGS values */ 111 + #define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ 112 + #define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ 113 + #define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ 114 + #define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ 115 + #define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ 116 + #define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ 117 + #define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ 118 + #define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */ 119 + #define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */ 120 + #define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ 121 + #define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */ 122 + #define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */ 123 + #define BCM43xx_BFL_EXTLNA 0x1000 /* has an external LNA */ 124 + #define BCM43xx_BFL_HGPA 0x2000 /* had high gain PA */ 125 + #define BCM43xx_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ 126 + #define BCM43xx_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ 127 + 128 + /* GPIO register offset, in both ChipCommon and PCI core. */ 129 + #define BCM43xx_GPIO_CONTROL 0x6c 130 + 131 + /* SHM Routing */ 132 + #define BCM43xx_SHM_SHARED 0x0001 133 + #define BCM43xx_SHM_WIRELESS 0x0002 134 + #define BCM43xx_SHM_PCM 0x0003 135 + #define BCM43xx_SHM_HWMAC 0x0004 136 + #define BCM43xx_SHM_UCODE 0x0300 137 + 138 + /* MacFilter offsets. */ 139 + #define BCM43xx_MACFILTER_SELF 0x0000 140 + #define BCM43xx_MACFILTER_ASSOC 0x0003 141 + 142 + /* Chipcommon registers. */ 143 + #define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04 144 + #define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0 145 + #define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4 146 + #define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8 147 + #define BCM43xx_CHIPCOMMON_SYSCLKCTL 0xC0 148 + 149 + /* PCI core specific registers. */ 150 + #define BCM43xx_PCICORE_BCAST_ADDR 0x50 151 + #define BCM43xx_PCICORE_BCAST_DATA 0x54 152 + #define BCM43xx_PCICORE_SBTOPCI2 0x108 153 + 154 + /* SBTOPCI2 values. */ 155 + #define BCM43xx_SBTOPCI2_PREFETCH 0x4 156 + #define BCM43xx_SBTOPCI2_BURST 0x8 157 + 158 + /* Chipcommon capabilities. */ 159 + #define BCM43xx_CAPABILITIES_PCTL 0x00040000 160 + #define BCM43xx_CAPABILITIES_PLLMASK 0x00030000 161 + #define BCM43xx_CAPABILITIES_PLLSHIFT 16 162 + #define BCM43xx_CAPABILITIES_FLASHMASK 0x00000700 163 + #define BCM43xx_CAPABILITIES_FLASHSHIFT 8 164 + #define BCM43xx_CAPABILITIES_EXTBUSPRESENT 0x00000040 165 + #define BCM43xx_CAPABILITIES_UARTGPIO 0x00000020 166 + #define BCM43xx_CAPABILITIES_UARTCLOCKMASK 0x00000018 167 + #define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT 3 168 + #define BCM43xx_CAPABILITIES_MIPSBIGENDIAN 0x00000004 169 + #define BCM43xx_CAPABILITIES_NRUARTSMASK 0x00000003 170 + 171 + /* PowerControl */ 172 + #define BCM43xx_PCTL_IN 0xB0 173 + #define BCM43xx_PCTL_OUT 0xB4 174 + #define BCM43xx_PCTL_OUTENABLE 0xB8 175 + #define BCM43xx_PCTL_XTAL_POWERUP 0x40 176 + #define BCM43xx_PCTL_PLL_POWERDOWN 0x80 177 + 178 + /* PowerControl Clock Modes */ 179 + #define BCM43xx_PCTL_CLK_FAST 0x00 180 + #define BCM43xx_PCTL_CLK_SLOW 0x01 181 + #define BCM43xx_PCTL_CLK_DYNAMIC 0x02 182 + 183 + #define BCM43xx_PCTL_FORCE_SLOW 0x0800 184 + #define BCM43xx_PCTL_FORCE_PLL 0x1000 185 + #define BCM43xx_PCTL_DYN_XTAL 0x2000 186 + 187 + /* COREIDs */ 188 + #define BCM43xx_COREID_CHIPCOMMON 0x800 189 + #define BCM43xx_COREID_ILINE20 0x801 190 + #define BCM43xx_COREID_SDRAM 0x803 191 + #define BCM43xx_COREID_PCI 0x804 192 + #define BCM43xx_COREID_MIPS 0x805 193 + #define BCM43xx_COREID_ETHERNET 0x806 194 + #define BCM43xx_COREID_V90 0x807 195 + #define BCM43xx_COREID_USB11_HOSTDEV 0x80a 196 + #define BCM43xx_COREID_IPSEC 0x80b 197 + #define BCM43xx_COREID_PCMCIA 0x80d 198 + #define BCM43xx_COREID_EXT_IF 0x80f 199 + #define BCM43xx_COREID_80211 0x812 200 + #define BCM43xx_COREID_MIPS_3302 0x816 201 + #define BCM43xx_COREID_USB11_HOST 0x817 202 + #define BCM43xx_COREID_USB11_DEV 0x818 203 + #define BCM43xx_COREID_USB20_HOST 0x819 204 + #define BCM43xx_COREID_USB20_DEV 0x81a 205 + #define BCM43xx_COREID_SDIO_HOST 0x81b 206 + 207 + /* Core Information Registers */ 208 + #define BCM43xx_CIR_BASE 0xf00 209 + #define BCM43xx_CIR_SBTPSFLAG (BCM43xx_CIR_BASE + 0x18) 210 + #define BCM43xx_CIR_SBIMSTATE (BCM43xx_CIR_BASE + 0x90) 211 + #define BCM43xx_CIR_SBINTVEC (BCM43xx_CIR_BASE + 0x94) 212 + #define BCM43xx_CIR_SBTMSTATELOW (BCM43xx_CIR_BASE + 0x98) 213 + #define BCM43xx_CIR_SBTMSTATEHIGH (BCM43xx_CIR_BASE + 0x9c) 214 + #define BCM43xx_CIR_SBIMCONFIGLOW (BCM43xx_CIR_BASE + 0xa8) 215 + #define BCM43xx_CIR_SB_ID_HI (BCM43xx_CIR_BASE + 0xfc) 216 + 217 + /* Mask to get the Backplane Flag Number from SBTPSFLAG. */ 218 + #define BCM43xx_BACKPLANE_FLAG_NR_MASK 0x3f 219 + 220 + /* SBIMCONFIGLOW values/masks. */ 221 + #define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK 0x00000007 222 + #define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT 0 223 + #define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK 0x00000070 224 + #define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT 4 225 + #define BCM43xx_SBIMCONFIGLOW_CONNID_MASK 0x00ff0000 226 + #define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT 16 227 + 228 + /* sbtmstatelow state flags */ 229 + #define BCM43xx_SBTMSTATELOW_RESET 0x01 230 + #define BCM43xx_SBTMSTATELOW_REJECT 0x02 231 + #define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 232 + #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 233 + 234 + /* sbtmstatehigh state flags */ 235 + #define BCM43xx_SBTMSTATEHIGH_SERROR 0x1 236 + #define BCM43xx_SBTMSTATEHIGH_BUSY 0x4 237 + 238 + /* sbimstate flags */ 239 + #define BCM43xx_SBIMSTATE_IB_ERROR 0x20000 240 + #define BCM43xx_SBIMSTATE_TIMEOUT 0x40000 241 + 242 + /* PHYVersioning */ 243 + #define BCM43xx_PHYTYPE_A 0x00 244 + #define BCM43xx_PHYTYPE_B 0x01 245 + #define BCM43xx_PHYTYPE_G 0x02 246 + 247 + /* PHYRegisters */ 248 + #define BCM43xx_PHY_ILT_A_CTRL 0x0072 249 + #define BCM43xx_PHY_ILT_A_DATA1 0x0073 250 + #define BCM43xx_PHY_ILT_A_DATA2 0x0074 251 + #define BCM43xx_PHY_G_LO_CONTROL 0x0810 252 + #define BCM43xx_PHY_ILT_G_CTRL 0x0472 253 + #define BCM43xx_PHY_ILT_G_DATA1 0x0473 254 + #define BCM43xx_PHY_ILT_G_DATA2 0x0474 255 + #define BCM43xx_PHY_A_PCTL 0x007B 256 + #define BCM43xx_PHY_G_PCTL 0x0029 257 + #define BCM43xx_PHY_A_CRS 0x0029 258 + #define BCM43xx_PHY_RADIO_BITFIELD 0x0401 259 + #define BCM43xx_PHY_G_CRS 0x0429 260 + #define BCM43xx_PHY_NRSSILT_CTRL 0x0803 261 + #define BCM43xx_PHY_NRSSILT_DATA 0x0804 262 + 263 + /* RadioRegisters */ 264 + #define BCM43xx_RADIOCTL_ID 0x01 265 + 266 + /* StatusBitField */ 267 + #define BCM43xx_SBF_MAC_ENABLED 0x00000001 268 + #define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/ 269 + #define BCM43xx_SBF_CORE_READY 0x00000004 270 + #define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/ 271 + #define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/ 272 + #define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/ 273 + #define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000 274 + #define BCM43xx_SBF_MODE_NOTADHOC 0x00020000 275 + #define BCM43xx_SBF_MODE_AP 0x00040000 276 + #define BCM43xx_SBF_RADIOREG_LOCK 0x00080000 277 + #define BCM43xx_SBF_MODE_MONITOR 0x00400000 278 + #define BCM43xx_SBF_MODE_PROMISC 0x01000000 279 + #define BCM43xx_SBF_PS1 0x02000000 280 + #define BCM43xx_SBF_PS2 0x04000000 281 + #define BCM43xx_SBF_NO_SSID_BCAST 0x08000000 282 + #define BCM43xx_SBF_TIME_UPDATE 0x10000000 283 + #define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/ 284 + 285 + /* MicrocodeFlagsBitfield (addr + lo-word values?)*/ 286 + #define BCM43xx_UCODEFLAGS_OFFSET 0x005E 287 + 288 + #define BCM43xx_UCODEFLAG_AUTODIV 0x0001 289 + #define BCM43xx_UCODEFLAG_UNKBGPHY 0x0002 290 + #define BCM43xx_UCODEFLAG_UNKBPHY 0x0004 291 + #define BCM43xx_UCODEFLAG_UNKGPHY 0x0020 292 + #define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040 293 + #define BCM43xx_UCODEFLAG_JAPAN 0x0080 294 + 295 + /* Generic-Interrupt reasons. */ 296 + #define BCM43xx_IRQ_READY (1 << 0) 297 + #define BCM43xx_IRQ_BEACON (1 << 1) 298 + #define BCM43xx_IRQ_PS (1 << 2) 299 + #define BCM43xx_IRQ_REG124 (1 << 5) 300 + #define BCM43xx_IRQ_PMQ (1 << 6) 301 + #define BCM43xx_IRQ_PIO_WORKAROUND (1 << 8) 302 + #define BCM43xx_IRQ_XMIT_ERROR (1 << 11) 303 + #define BCM43xx_IRQ_RX (1 << 15) 304 + #define BCM43xx_IRQ_SCAN (1 << 16) 305 + #define BCM43xx_IRQ_NOISE (1 << 18) 306 + #define BCM43xx_IRQ_XMIT_STATUS (1 << 29) 307 + 308 + #define BCM43xx_IRQ_ALL 0xffffffff 309 + #define BCM43xx_IRQ_INITIAL (BCM43xx_IRQ_PS | \ 310 + BCM43xx_IRQ_REG124 | \ 311 + BCM43xx_IRQ_PMQ | \ 312 + BCM43xx_IRQ_XMIT_ERROR | \ 313 + BCM43xx_IRQ_RX | \ 314 + BCM43xx_IRQ_SCAN | \ 315 + BCM43xx_IRQ_NOISE | \ 316 + BCM43xx_IRQ_XMIT_STATUS) 317 + 318 + 319 + /* Initial default iw_mode */ 320 + #define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA 321 + 322 + /* Bus type PCI. */ 323 + #define BCM43xx_BUSTYPE_PCI 0 324 + /* Bus type Silicone Backplane Bus. */ 325 + #define BCM43xx_BUSTYPE_SB 1 326 + /* Bus type PCMCIA. */ 327 + #define BCM43xx_BUSTYPE_PCMCIA 2 328 + 329 + /* Threshold values. */ 330 + #define BCM43xx_MIN_RTS_THRESHOLD 1U 331 + #define BCM43xx_MAX_RTS_THRESHOLD 2304U 332 + #define BCM43xx_DEFAULT_RTS_THRESHOLD BCM43xx_MAX_RTS_THRESHOLD 333 + 334 + #define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7 335 + #define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4 336 + 337 + /* Max size of a security key */ 338 + #define BCM43xx_SEC_KEYSIZE 16 339 + /* Security algorithms. */ 340 + enum { 341 + BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ 342 + BCM43xx_SEC_ALGO_WEP, 343 + BCM43xx_SEC_ALGO_UNKNOWN, 344 + BCM43xx_SEC_ALGO_AES, 345 + BCM43xx_SEC_ALGO_WEP104, 346 + BCM43xx_SEC_ALGO_TKIP, 347 + }; 348 + 349 + #ifdef assert 350 + # undef assert 351 + #endif 352 + #ifdef CONFIG_BCM43XX_DEBUG 353 + #define assert(expr) \ 354 + do { \ 355 + if (unlikely(!(expr))) { \ 356 + printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \ 357 + #expr, __FILE__, __LINE__, __FUNCTION__); \ 358 + } \ 359 + } while (0) 360 + #else 361 + #define assert(expr) do { /* nothing */ } while (0) 362 + #endif 363 + 364 + /* rate limited printk(). */ 365 + #ifdef printkl 366 + # undef printkl 367 + #endif 368 + #define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0) 369 + /* rate limited printk() for debugging */ 370 + #ifdef dprintkl 371 + # undef dprintkl 372 + #endif 373 + #ifdef CONFIG_BCM43XX_DEBUG 374 + # define dprintkl printkl 375 + #else 376 + # define dprintkl(f, x...) do { /* nothing */ } while (0) 377 + #endif 378 + 379 + /* Helper macro for if branches. 380 + * An if branch marked with this macro is only taken in DEBUG mode. 381 + * Example: 382 + * if (DEBUG_ONLY(foo == bar)) { 383 + * do something 384 + * } 385 + * In DEBUG mode, the branch will be taken if (foo == bar). 386 + * In non-DEBUG mode, the branch will never be taken. 387 + */ 388 + #ifdef DEBUG_ONLY 389 + # undef DEBUG_ONLY 390 + #endif 391 + #ifdef CONFIG_BCM43XX_DEBUG 392 + # define DEBUG_ONLY(x) (x) 393 + #else 394 + # define DEBUG_ONLY(x) 0 395 + #endif 396 + 397 + /* debugging printk() */ 398 + #ifdef dprintk 399 + # undef dprintk 400 + #endif 401 + #ifdef CONFIG_BCM43XX_DEBUG 402 + # define dprintk(f, x...) do { printk(f ,##x); } while (0) 403 + #else 404 + # define dprintk(f, x...) do { /* nothing */ } while (0) 405 + #endif 406 + 407 + 408 + struct net_device; 409 + struct pci_dev; 410 + struct bcm43xx_dmaring; 411 + struct bcm43xx_pioqueue; 412 + 413 + struct bcm43xx_initval { 414 + u16 offset; 415 + u16 size; 416 + u32 value; 417 + } __attribute__((__packed__)); 418 + 419 + /* Values for bcm430x_sprominfo.locale */ 420 + enum { 421 + BCM43xx_LOCALE_WORLD = 0, 422 + BCM43xx_LOCALE_THAILAND, 423 + BCM43xx_LOCALE_ISRAEL, 424 + BCM43xx_LOCALE_JORDAN, 425 + BCM43xx_LOCALE_CHINA, 426 + BCM43xx_LOCALE_JAPAN, 427 + BCM43xx_LOCALE_USA_CANADA_ANZ, 428 + BCM43xx_LOCALE_EUROPE, 429 + BCM43xx_LOCALE_USA_LOW, 430 + BCM43xx_LOCALE_JAPAN_HIGH, 431 + BCM43xx_LOCALE_ALL, 432 + BCM43xx_LOCALE_NONE, 433 + }; 434 + 435 + #define BCM43xx_SPROM_SIZE 64 /* in 16-bit words. */ 436 + struct bcm43xx_sprominfo { 437 + u16 boardflags2; 438 + u8 il0macaddr[6]; 439 + u8 et0macaddr[6]; 440 + u8 et1macaddr[6]; 441 + u8 et0phyaddr:5; 442 + u8 et1phyaddr:5; 443 + u8 et0mdcport:1; 444 + u8 et1mdcport:1; 445 + u8 boardrev; 446 + u8 locale:4; 447 + u8 antennas_aphy:2; 448 + u8 antennas_bgphy:2; 449 + u16 pa0b0; 450 + u16 pa0b1; 451 + u16 pa0b2; 452 + u8 wl0gpio0; 453 + u8 wl0gpio1; 454 + u8 wl0gpio2; 455 + u8 wl0gpio3; 456 + u8 maxpower_aphy; 457 + u8 maxpower_bgphy; 458 + u16 pa1b0; 459 + u16 pa1b1; 460 + u16 pa1b2; 461 + u8 idle_tssi_tgt_aphy; 462 + u8 idle_tssi_tgt_bgphy; 463 + u16 boardflags; 464 + u16 antennagain_aphy; 465 + u16 antennagain_bgphy; 466 + }; 467 + 468 + /* Value pair to measure the LocalOscillator. */ 469 + struct bcm43xx_lopair { 470 + s8 low; 471 + s8 high; 472 + u8 used:1; 473 + }; 474 + #define BCM43xx_LO_COUNT (14*4) 475 + 476 + struct bcm43xx_phyinfo { 477 + /* Hardware Data */ 478 + u8 version; 479 + u8 type; 480 + u8 rev; 481 + u16 antenna_diversity; 482 + u16 savedpctlreg; 483 + u16 minlowsig[2]; 484 + u16 minlowsigpos[2]; 485 + u8 connected:1, 486 + calibrated:1, 487 + is_locked:1, /* used in bcm43xx_phy_{un}lock() */ 488 + dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */ 489 + /* LO Measurement Data. 490 + * Use bcm43xx_get_lopair() to get a value. 491 + */ 492 + struct bcm43xx_lopair *_lo_pairs; 493 + 494 + /* TSSI to dBm table in use */ 495 + const s8 *tssi2dbm; 496 + /* idle TSSI value */ 497 + s8 idle_tssi; 498 + 499 + /* Values from bcm43xx_calc_loopback_gain() */ 500 + u16 loopback_gain[2]; 501 + 502 + /* PHY lock for core.rev < 3 503 + * This lock is only used by bcm43xx_phy_{un}lock() 504 + */ 505 + spinlock_t lock; 506 + }; 507 + 508 + 509 + struct bcm43xx_radioinfo { 510 + u16 manufact; 511 + u16 version; 512 + u8 revision; 513 + 514 + /* Desired TX power in dBm Q5.2 */ 515 + u16 txpower_desired; 516 + /* TX Power control values. */ 517 + union { 518 + /* B/G PHY */ 519 + struct { 520 + u16 baseband_atten; 521 + u16 radio_atten; 522 + u16 txctl1; 523 + u16 txctl2; 524 + }; 525 + /* A PHY */ 526 + struct { 527 + u16 txpwr_offset; 528 + }; 529 + }; 530 + 531 + /* Current Interference Mitigation mode */ 532 + int interfmode; 533 + /* Stack of saved values from the Interference Mitigation code. 534 + * Each value in the stack is layed out as follows: 535 + * bit 0-11: offset 536 + * bit 12-15: register ID 537 + * bit 16-32: value 538 + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT 539 + */ 540 + #define BCM43xx_INTERFSTACK_SIZE 26 541 + u32 interfstack[BCM43xx_INTERFSTACK_SIZE]; 542 + 543 + /* Saved values from the NRSSI Slope calculation */ 544 + s16 nrssi[2]; 545 + s32 nrssislope; 546 + /* In memory nrssi lookup table. */ 547 + s8 nrssi_lt[64]; 548 + 549 + /* current channel */ 550 + u8 channel; 551 + u8 initial_channel; 552 + 553 + u16 lofcal; 554 + 555 + u16 initval; 556 + 557 + u8 enabled:1; 558 + /* ACI (adjacent channel interference) flags. */ 559 + u8 aci_enable:1, 560 + aci_wlan_automatic:1, 561 + aci_hw_rssi:1; 562 + }; 563 + 564 + /* Data structures for DMA transmission, per 80211 core. */ 565 + struct bcm43xx_dma { 566 + struct bcm43xx_dmaring *tx_ring0; 567 + struct bcm43xx_dmaring *tx_ring1; 568 + struct bcm43xx_dmaring *tx_ring2; 569 + struct bcm43xx_dmaring *tx_ring3; 570 + struct bcm43xx_dmaring *rx_ring0; 571 + struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */ 572 + }; 573 + 574 + /* Data structures for PIO transmission, per 80211 core. */ 575 + struct bcm43xx_pio { 576 + struct bcm43xx_pioqueue *queue0; 577 + struct bcm43xx_pioqueue *queue1; 578 + struct bcm43xx_pioqueue *queue2; 579 + struct bcm43xx_pioqueue *queue3; 580 + }; 581 + 582 + #define BCM43xx_MAX_80211_CORES 2 583 + 584 + #ifdef CONFIG_BCM947XX 585 + #define core_offset(bcm) (bcm)->current_core_offset 586 + #else 587 + #define core_offset(bcm) 0 588 + #endif 589 + 590 + /* Generic information about a core. */ 591 + struct bcm43xx_coreinfo { 592 + u8 available:1, 593 + enabled:1, 594 + initialized:1; 595 + /** core_id ID number */ 596 + u16 id; 597 + /** core_rev revision number */ 598 + u8 rev; 599 + /** Index number for _switch_core() */ 600 + u8 index; 601 + }; 602 + 603 + /* Additional information for each 80211 core. */ 604 + struct bcm43xx_coreinfo_80211 { 605 + /* PHY device. */ 606 + struct bcm43xx_phyinfo phy; 607 + /* Radio device. */ 608 + struct bcm43xx_radioinfo radio; 609 + union { 610 + /* DMA context. */ 611 + struct bcm43xx_dma dma; 612 + /* PIO context. */ 613 + struct bcm43xx_pio pio; 614 + }; 615 + }; 616 + 617 + /* Context information for a noise calculation (Link Quality). */ 618 + struct bcm43xx_noise_calculation { 619 + struct bcm43xx_coreinfo *core_at_start; 620 + u8 channel_at_start; 621 + u8 calculation_running:1; 622 + u8 nr_samples; 623 + s8 samples[8][4]; 624 + }; 625 + 626 + struct bcm43xx_stats { 627 + u8 link_quality; 628 + u8 noise; 629 + struct iw_statistics wstats; 630 + /* Store the last TX/RX times here for updating the leds. */ 631 + unsigned long last_tx; 632 + unsigned long last_rx; 633 + }; 634 + 635 + struct bcm43xx_key { 636 + u8 enabled:1; 637 + u8 algorithm; 638 + }; 639 + 640 + struct bcm43xx_private { 641 + struct bcm43xx_sysfs sysfs; 642 + 643 + struct ieee80211_device *ieee; 644 + struct ieee80211softmac_device *softmac; 645 + 646 + struct net_device *net_dev; 647 + struct pci_dev *pci_dev; 648 + unsigned int irq; 649 + 650 + void __iomem *mmio_addr; 651 + unsigned int mmio_len; 652 + 653 + /* Do not use the lock directly. Use the bcm43xx_lock* helper 654 + * functions, to be MMIO-safe. */ 655 + spinlock_t _lock; 656 + 657 + /* Driver status flags. */ 658 + u32 initialized:1, /* init_board() succeed */ 659 + was_initialized:1, /* for PCI suspend/resume. */ 660 + shutting_down:1, /* free_board() in progress */ 661 + __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ 662 + bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ 663 + reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ 664 + powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ 665 + short_preamble:1, /* TRUE, if short preamble is enabled. */ 666 + firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ 667 + 668 + struct bcm43xx_stats stats; 669 + 670 + /* Bus type we are connected to. 671 + * This is currently always BCM43xx_BUSTYPE_PCI 672 + */ 673 + u8 bustype; 674 + 675 + u16 board_vendor; 676 + u16 board_type; 677 + u16 board_revision; 678 + 679 + u16 chip_id; 680 + u8 chip_rev; 681 + u8 chip_package; 682 + 683 + struct bcm43xx_sprominfo sprom; 684 + #define BCM43xx_NR_LEDS 4 685 + struct bcm43xx_led leds[BCM43xx_NR_LEDS]; 686 + 687 + /* The currently active core. */ 688 + struct bcm43xx_coreinfo *current_core; 689 + #ifdef CONFIG_BCM947XX 690 + /** current core memory offset */ 691 + u32 current_core_offset; 692 + #endif 693 + struct bcm43xx_coreinfo *active_80211_core; 694 + /* coreinfo structs for all possible cores follow. 695 + * Note that a core might not exist. 696 + * So check the coreinfo flags before using it. 697 + */ 698 + struct bcm43xx_coreinfo core_chipcommon; 699 + struct bcm43xx_coreinfo core_pci; 700 + struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; 701 + /* Additional information, specific to the 80211 cores. */ 702 + struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; 703 + /* Index of the current 80211 core. If current_core is not 704 + * an 80211 core, this is -1. 705 + */ 706 + int current_80211_core_idx; 707 + /* Number of available 80211 cores. */ 708 + int nr_80211_available; 709 + 710 + u32 chipcommon_capabilities; 711 + 712 + /* Reason code of the last interrupt. */ 713 + u32 irq_reason; 714 + u32 dma_reason[4]; 715 + /* saved irq enable/disable state bitfield. */ 716 + u32 irq_savedstate; 717 + /* Link Quality calculation context. */ 718 + struct bcm43xx_noise_calculation noisecalc; 719 + 720 + /* Threshold values. */ 721 + //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. 722 + u32 rts_threshold; 723 + 724 + /* Interrupt Service Routine tasklet (bottom-half) */ 725 + struct tasklet_struct isr_tasklet; 726 + 727 + /* Periodic tasks */ 728 + struct timer_list periodic_tasks; 729 + unsigned int periodic_state; 730 + 731 + struct work_struct restart_work; 732 + 733 + /* Informational stuff. */ 734 + char nick[IW_ESSID_MAX_SIZE + 1]; 735 + 736 + /* encryption/decryption */ 737 + u16 security_offset; 738 + struct bcm43xx_key key[54]; 739 + u8 default_key_idx; 740 + 741 + /* Firmware. */ 742 + const struct firmware *ucode; 743 + const struct firmware *pcm; 744 + const struct firmware *initvals0; 745 + const struct firmware *initvals1; 746 + 747 + /* Debugging stuff follows. */ 748 + #ifdef CONFIG_BCM43XX_DEBUG 749 + struct bcm43xx_dfsentry *dfsentry; 750 + #endif 751 + }; 752 + 753 + /* bcm43xx_(un)lock() protect struct bcm43xx_private. 754 + * Note that _NO_ MMIO writes are allowed. If you want to 755 + * write to the device through MMIO in the critical section, use 756 + * the *_mmio lock functions. 757 + * MMIO read-access is allowed, though. 758 + */ 759 + #define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags) 760 + #define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags) 761 + /* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO. 762 + * MMIO write-access to the device is allowed. 763 + * All MMIO writes are flushed on unlock, so it is guaranteed to not 764 + * interfere with other threads writing MMIO registers. 765 + */ 766 + #define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags) 767 + #define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0) 768 + 769 + static inline 770 + struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) 771 + { 772 + return ieee80211softmac_priv(dev); 773 + } 774 + 775 + 776 + /* Helper function, which returns a boolean. 777 + * TRUE, if PIO is used; FALSE, if DMA is used. 778 + */ 779 + #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) 780 + static inline 781 + int bcm43xx_using_pio(struct bcm43xx_private *bcm) 782 + { 783 + return bcm->__using_pio; 784 + } 785 + #elif defined(CONFIG_BCM43XX_DMA) 786 + static inline 787 + int bcm43xx_using_pio(struct bcm43xx_private *bcm) 788 + { 789 + return 0; 790 + } 791 + #elif defined(CONFIG_BCM43XX_PIO) 792 + static inline 793 + int bcm43xx_using_pio(struct bcm43xx_private *bcm) 794 + { 795 + return 1; 796 + } 797 + #else 798 + # error "Using neither DMA nor PIO? Confused..." 799 + #endif 800 + 801 + /* Helper functions to access data structures private to the 80211 cores. 802 + * Note that we _must_ have an 80211 core mapped when calling 803 + * any of these functions. 804 + */ 805 + static inline 806 + struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) 807 + { 808 + assert(bcm43xx_using_pio(bcm)); 809 + assert(bcm->current_80211_core_idx >= 0); 810 + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); 811 + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio); 812 + } 813 + static inline 814 + struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) 815 + { 816 + assert(!bcm43xx_using_pio(bcm)); 817 + assert(bcm->current_80211_core_idx >= 0); 818 + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); 819 + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma); 820 + } 821 + static inline 822 + struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) 823 + { 824 + assert(bcm->current_80211_core_idx >= 0); 825 + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); 826 + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy); 827 + } 828 + static inline 829 + struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) 830 + { 831 + assert(bcm->current_80211_core_idx >= 0); 832 + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); 833 + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); 834 + } 835 + 836 + /* Are we running in init_board() context? */ 837 + static inline 838 + int bcm43xx_is_initializing(struct bcm43xx_private *bcm) 839 + { 840 + if (bcm->initialized) 841 + return 0; 842 + if (bcm->shutting_down) 843 + return 0; 844 + return 1; 845 + } 846 + 847 + static inline 848 + struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, 849 + u16 radio_attenuation, 850 + u16 baseband_attenuation) 851 + { 852 + return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2)); 853 + } 854 + 855 + 856 + static inline 857 + u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) 858 + { 859 + return ioread16(bcm->mmio_addr + core_offset(bcm) + offset); 860 + } 861 + 862 + static inline 863 + void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value) 864 + { 865 + iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset); 866 + } 867 + 868 + static inline 869 + u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset) 870 + { 871 + return ioread32(bcm->mmio_addr + core_offset(bcm) + offset); 872 + } 873 + 874 + static inline 875 + void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value) 876 + { 877 + iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset); 878 + } 879 + 880 + static inline 881 + int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value) 882 + { 883 + return pci_read_config_word(bcm->pci_dev, offset, value); 884 + } 885 + 886 + static inline 887 + int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value) 888 + { 889 + return pci_read_config_dword(bcm->pci_dev, offset, value); 890 + } 891 + 892 + static inline 893 + int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value) 894 + { 895 + return pci_write_config_word(bcm->pci_dev, offset, value); 896 + } 897 + 898 + static inline 899 + int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value) 900 + { 901 + return pci_write_config_dword(bcm->pci_dev, offset, value); 902 + } 903 + 904 + /** Limit a value between two limits */ 905 + #ifdef limit_value 906 + # undef limit_value 907 + #endif 908 + #define limit_value(value, min, max) \ 909 + ({ \ 910 + typeof(value) __value = (value); \ 911 + typeof(value) __min = (min); \ 912 + typeof(value) __max = (max); \ 913 + if (__value < __min) \ 914 + __value = __min; \ 915 + else if (__value > __max) \ 916 + __value = __max; \ 917 + __value; \ 918 + }) 919 + 920 + /** Helpers to print MAC addresses. */ 921 + #define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x" 922 + #define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \ 923 + ((u8*)(x))[2], ((u8*)(x))[3], \ 924 + ((u8*)(x))[4], ((u8*)(x))[5] 925 + 926 + #endif /* BCM43xx_H_ */
+499
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + debugfs driver debugging code 6 + 7 + Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de> 8 + 9 + This program is free software; you can redistribute it and/or modify 10 + it under the terms of the GNU General Public License as published by 11 + the Free Software Foundation; either version 2 of the License, or 12 + (at your option) any later version. 13 + 14 + This program is distributed in the hope that it will be useful, 15 + but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + GNU General Public License for more details. 18 + 19 + You should have received a copy of the GNU General Public License 20 + along with this program; see the file COPYING. If not, write to 21 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 22 + Boston, MA 02110-1301, USA. 23 + 24 + */ 25 + 26 + 27 + 28 + #include <linux/fs.h> 29 + #include <linux/debugfs.h> 30 + #include <linux/slab.h> 31 + #include <linux/netdevice.h> 32 + #include <linux/pci.h> 33 + #include <asm/io.h> 34 + 35 + #include "bcm43xx.h" 36 + #include "bcm43xx_main.h" 37 + #include "bcm43xx_debugfs.h" 38 + #include "bcm43xx_dma.h" 39 + #include "bcm43xx_pio.h" 40 + #include "bcm43xx_xmit.h" 41 + 42 + #define REALLY_BIG_BUFFER_SIZE (1024*256) 43 + 44 + static struct bcm43xx_debugfs fs; 45 + static char really_big_buffer[REALLY_BIG_BUFFER_SIZE]; 46 + static DECLARE_MUTEX(big_buffer_sem); 47 + 48 + 49 + static ssize_t write_file_dummy(struct file *file, const char __user *buf, 50 + size_t count, loff_t *ppos) 51 + { 52 + return count; 53 + } 54 + 55 + static int open_file_generic(struct inode *inode, struct file *file) 56 + { 57 + file->private_data = inode->u.generic_ip; 58 + return 0; 59 + } 60 + 61 + #define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x) 62 + 63 + static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, 64 + size_t count, loff_t *ppos) 65 + { 66 + const size_t len = REALLY_BIG_BUFFER_SIZE; 67 + 68 + struct bcm43xx_private *bcm = file->private_data; 69 + char *buf = really_big_buffer; 70 + size_t pos = 0; 71 + ssize_t res; 72 + struct net_device *net_dev; 73 + struct pci_dev *pci_dev; 74 + unsigned long flags; 75 + u16 tmp16; 76 + int i; 77 + 78 + down(&big_buffer_sem); 79 + 80 + bcm43xx_lock_mmio(bcm, flags); 81 + if (!bcm->initialized) { 82 + fappend("Board not initialized.\n"); 83 + goto out; 84 + } 85 + net_dev = bcm->net_dev; 86 + pci_dev = bcm->pci_dev; 87 + 88 + /* This is where the information is written to the "devinfo" file */ 89 + fappend("*** %s devinfo ***\n", net_dev->name); 90 + fappend("vendor: 0x%04x device: 0x%04x\n", 91 + pci_dev->vendor, pci_dev->device); 92 + fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n", 93 + pci_dev->subsystem_vendor, pci_dev->subsystem_device); 94 + fappend("IRQ: %d\n", bcm->irq); 95 + fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len); 96 + fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev); 97 + if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16))) 98 + fappend("Radio disabled by hardware!\n"); 99 + if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4))) 100 + fappend("Radio disabled by hardware!\n"); 101 + fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor, 102 + bcm->board_type); 103 + 104 + fappend("\nCores:\n"); 105 + #define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ 106 + "rev: 0x%02x, index: 0x%02x\n", \ 107 + (info).available \ 108 + ? "available" : "nonavailable", \ 109 + (info).enabled \ 110 + ? "enabled" : "disabled", \ 111 + (info).id, (info).rev, (info).index) 112 + fappend_core("CHIPCOMMON", bcm->core_chipcommon); 113 + fappend_core("PCI", bcm->core_pci); 114 + fappend_core("first 80211", bcm->core_80211[0]); 115 + fappend_core("second 80211", bcm->core_80211[1]); 116 + #undef fappend_core 117 + tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); 118 + fappend("LEDs: "); 119 + for (i = 0; i < BCM43xx_NR_LEDS; i++) 120 + fappend("%d ", !!(tmp16 & (1 << i))); 121 + fappend("\n"); 122 + 123 + out: 124 + bcm43xx_unlock_mmio(bcm, flags); 125 + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 126 + up(&big_buffer_sem); 127 + return res; 128 + } 129 + 130 + static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, 131 + size_t count, loff_t *ppos) 132 + { 133 + const size_t len = REALLY_BIG_BUFFER_SIZE; 134 + 135 + char *buf = really_big_buffer; 136 + size_t pos = 0; 137 + ssize_t res; 138 + 139 + down(&big_buffer_sem); 140 + 141 + /* This is where the information is written to the "driver" file */ 142 + fappend(KBUILD_MODNAME " driver\n"); 143 + fappend("Compiled at: %s %s\n", __DATE__, __TIME__); 144 + 145 + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 146 + up(&big_buffer_sem); 147 + return res; 148 + } 149 + 150 + static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, 151 + size_t count, loff_t *ppos) 152 + { 153 + const size_t len = REALLY_BIG_BUFFER_SIZE; 154 + 155 + struct bcm43xx_private *bcm = file->private_data; 156 + char *buf = really_big_buffer; 157 + size_t pos = 0; 158 + ssize_t res; 159 + unsigned long flags; 160 + 161 + down(&big_buffer_sem); 162 + bcm43xx_lock_mmio(bcm, flags); 163 + if (!bcm->initialized) { 164 + fappend("Board not initialized.\n"); 165 + goto out; 166 + } 167 + 168 + /* This is where the information is written to the "sprom_dump" file */ 169 + fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); 170 + 171 + out: 172 + bcm43xx_unlock_mmio(bcm, flags); 173 + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 174 + up(&big_buffer_sem); 175 + return res; 176 + } 177 + 178 + static ssize_t tsf_read_file(struct file *file, char __user *userbuf, 179 + size_t count, loff_t *ppos) 180 + { 181 + const size_t len = REALLY_BIG_BUFFER_SIZE; 182 + 183 + struct bcm43xx_private *bcm = file->private_data; 184 + char *buf = really_big_buffer; 185 + size_t pos = 0; 186 + ssize_t res; 187 + unsigned long flags; 188 + u64 tsf; 189 + 190 + down(&big_buffer_sem); 191 + bcm43xx_lock_mmio(bcm, flags); 192 + if (!bcm->initialized) { 193 + fappend("Board not initialized.\n"); 194 + goto out; 195 + } 196 + bcm43xx_tsf_read(bcm, &tsf); 197 + fappend("0x%08x%08x\n", 198 + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), 199 + (unsigned int)(tsf & 0xFFFFFFFFULL)); 200 + 201 + out: 202 + bcm43xx_unlock_mmio(bcm, flags); 203 + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 204 + up(&big_buffer_sem); 205 + return res; 206 + } 207 + 208 + static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, 209 + size_t count, loff_t *ppos) 210 + { 211 + struct bcm43xx_private *bcm = file->private_data; 212 + char *buf = really_big_buffer; 213 + ssize_t buf_size; 214 + ssize_t res; 215 + unsigned long flags; 216 + u64 tsf; 217 + 218 + buf_size = min(count, sizeof (really_big_buffer) - 1); 219 + down(&big_buffer_sem); 220 + if (copy_from_user(buf, user_buf, buf_size)) { 221 + res = -EFAULT; 222 + goto out_up; 223 + } 224 + bcm43xx_lock_mmio(bcm, flags); 225 + if (!bcm->initialized) { 226 + printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); 227 + res = -EFAULT; 228 + goto out_unlock; 229 + } 230 + if (sscanf(buf, "%lli", &tsf) != 1) { 231 + printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n"); 232 + res = -EINVAL; 233 + goto out_unlock; 234 + } 235 + bcm43xx_tsf_write(bcm, tsf); 236 + res = buf_size; 237 + 238 + out_unlock: 239 + bcm43xx_unlock_mmio(bcm, flags); 240 + out_up: 241 + up(&big_buffer_sem); 242 + return res; 243 + } 244 + 245 + static ssize_t txstat_read_file(struct file *file, char __user *userbuf, 246 + size_t count, loff_t *ppos) 247 + { 248 + const size_t len = REALLY_BIG_BUFFER_SIZE; 249 + 250 + struct bcm43xx_private *bcm = file->private_data; 251 + char *buf = really_big_buffer; 252 + size_t pos = 0; 253 + ssize_t res; 254 + unsigned long flags; 255 + struct bcm43xx_dfsentry *e; 256 + struct bcm43xx_xmitstatus *status; 257 + int i, cnt, j = 0; 258 + 259 + down(&big_buffer_sem); 260 + bcm43xx_lock(bcm, flags); 261 + 262 + fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", 263 + BCM43xx_NR_LOGGED_XMITSTATUS); 264 + e = bcm->dfsentry; 265 + if (e->xmitstatus_printing == 0) { 266 + /* At the beginning, make a copy of all data to avoid 267 + * concurrency, as this function is called multiple 268 + * times for big logs. Without copying, the data might 269 + * change between reads. This would result in total trash. 270 + */ 271 + e->xmitstatus_printing = 1; 272 + e->saved_xmitstatus_ptr = e->xmitstatus_ptr; 273 + e->saved_xmitstatus_cnt = e->xmitstatus_cnt; 274 + memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer, 275 + BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer))); 276 + } 277 + i = e->saved_xmitstatus_ptr - 1; 278 + if (i < 0) 279 + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; 280 + cnt = e->saved_xmitstatus_cnt; 281 + while (cnt) { 282 + status = e->xmitstatus_print_buffer + i; 283 + fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, " 284 + "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, " 285 + "unk: 0x%04x\n", j, 286 + status->cookie, status->flags, 287 + status->cnt1, status->cnt2, status->seq, 288 + status->unknown); 289 + j++; 290 + cnt--; 291 + i--; 292 + if (i < 0) 293 + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; 294 + } 295 + 296 + bcm43xx_unlock(bcm, flags); 297 + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 298 + bcm43xx_lock(bcm, flags); 299 + if (*ppos == pos) { 300 + /* Done. Drop the copied data. */ 301 + e->xmitstatus_printing = 0; 302 + } 303 + bcm43xx_unlock(bcm, flags); 304 + up(&big_buffer_sem); 305 + return res; 306 + } 307 + 308 + #undef fappend 309 + 310 + 311 + static struct file_operations devinfo_fops = { 312 + .read = devinfo_read_file, 313 + .write = write_file_dummy, 314 + .open = open_file_generic, 315 + }; 316 + 317 + static struct file_operations spromdump_fops = { 318 + .read = spromdump_read_file, 319 + .write = write_file_dummy, 320 + .open = open_file_generic, 321 + }; 322 + 323 + static struct file_operations drvinfo_fops = { 324 + .read = drvinfo_read_file, 325 + .write = write_file_dummy, 326 + .open = open_file_generic, 327 + }; 328 + 329 + static struct file_operations tsf_fops = { 330 + .read = tsf_read_file, 331 + .write = tsf_write_file, 332 + .open = open_file_generic, 333 + }; 334 + 335 + static struct file_operations txstat_fops = { 336 + .read = txstat_read_file, 337 + .write = write_file_dummy, 338 + .open = open_file_generic, 339 + }; 340 + 341 + 342 + void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) 343 + { 344 + struct bcm43xx_dfsentry *e; 345 + char devdir[IFNAMSIZ]; 346 + 347 + assert(bcm); 348 + e = kzalloc(sizeof(*e), GFP_KERNEL); 349 + if (!e) { 350 + printk(KERN_ERR PFX "out of memory\n"); 351 + return; 352 + } 353 + e->bcm = bcm; 354 + e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS 355 + * sizeof(*(e->xmitstatus_buffer)), 356 + GFP_KERNEL); 357 + if (!e->xmitstatus_buffer) { 358 + printk(KERN_ERR PFX "out of memory\n"); 359 + kfree(e); 360 + return; 361 + } 362 + e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS 363 + * sizeof(*(e->xmitstatus_buffer)), 364 + GFP_KERNEL); 365 + if (!e->xmitstatus_print_buffer) { 366 + printk(KERN_ERR PFX "out of memory\n"); 367 + kfree(e); 368 + return; 369 + } 370 + 371 + 372 + bcm->dfsentry = e; 373 + 374 + strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir)); 375 + e->subdir = debugfs_create_dir(devdir, fs.root); 376 + e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir, 377 + bcm, &devinfo_fops); 378 + if (!e->dentry_devinfo) 379 + printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir); 380 + e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir, 381 + bcm, &spromdump_fops); 382 + if (!e->dentry_spromdump) 383 + printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir); 384 + e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir, 385 + bcm, &tsf_fops); 386 + if (!e->dentry_tsf) 387 + printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir); 388 + e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir, 389 + bcm, &txstat_fops); 390 + if (!e->dentry_txstat) 391 + printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); 392 + } 393 + 394 + void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) 395 + { 396 + struct bcm43xx_dfsentry *e; 397 + 398 + if (!bcm) 399 + return; 400 + 401 + e = bcm->dfsentry; 402 + assert(e); 403 + debugfs_remove(e->dentry_spromdump); 404 + debugfs_remove(e->dentry_devinfo); 405 + debugfs_remove(e->dentry_tsf); 406 + debugfs_remove(e->dentry_txstat); 407 + debugfs_remove(e->subdir); 408 + kfree(e->xmitstatus_buffer); 409 + kfree(e->xmitstatus_print_buffer); 410 + kfree(e); 411 + } 412 + 413 + void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, 414 + struct bcm43xx_xmitstatus *status) 415 + { 416 + struct bcm43xx_dfsentry *e; 417 + struct bcm43xx_xmitstatus *savedstatus; 418 + 419 + /* This is protected by bcm->_lock */ 420 + e = bcm->dfsentry; 421 + assert(e); 422 + savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr; 423 + memcpy(savedstatus, status, sizeof(*status)); 424 + e->xmitstatus_ptr++; 425 + if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS) 426 + e->xmitstatus_ptr = 0; 427 + if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS) 428 + e->xmitstatus_cnt++; 429 + } 430 + 431 + void bcm43xx_debugfs_init(void) 432 + { 433 + memset(&fs, 0, sizeof(fs)); 434 + fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL); 435 + if (!fs.root) 436 + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n"); 437 + fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); 438 + if (!fs.dentry_driverinfo) 439 + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n"); 440 + } 441 + 442 + void bcm43xx_debugfs_exit(void) 443 + { 444 + debugfs_remove(fs.dentry_driverinfo); 445 + debugfs_remove(fs.root); 446 + } 447 + 448 + void bcm43xx_printk_dump(const char *data, 449 + size_t size, 450 + const char *description) 451 + { 452 + size_t i; 453 + char c; 454 + 455 + printk(KERN_INFO PFX "Data dump (%s, %u bytes):", 456 + description, size); 457 + for (i = 0; i < size; i++) { 458 + c = data[i]; 459 + if (i % 8 == 0) 460 + printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff); 461 + else 462 + printk("0x%02x, ", c & 0xff); 463 + } 464 + printk("\n"); 465 + } 466 + 467 + void bcm43xx_printk_bitdump(const unsigned char *data, 468 + size_t bytes, int msb_to_lsb, 469 + const char *description) 470 + { 471 + size_t i; 472 + int j; 473 + const unsigned char *d; 474 + 475 + printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***", 476 + description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); 477 + for (i = 0; i < bytes; i++) { 478 + d = data + i; 479 + if (i % 8 == 0) 480 + printk("\n" KERN_INFO PFX "0x%08x: ", i); 481 + if (msb_to_lsb) { 482 + for (j = 7; j >= 0; j--) { 483 + if (*d & (1 << j)) 484 + printk("1"); 485 + else 486 + printk("0"); 487 + } 488 + } else { 489 + for (j = 0; j < 8; j++) { 490 + if (*d & (1 << j)) 491 + printk("1"); 492 + else 493 + printk("0"); 494 + } 495 + } 496 + printk(" "); 497 + } 498 + printk("\n"); 499 + }
+117
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
··· 1 + #ifndef BCM43xx_DEBUGFS_H_ 2 + #define BCM43xx_DEBUGFS_H_ 3 + 4 + struct bcm43xx_private; 5 + struct bcm43xx_xmitstatus; 6 + 7 + #ifdef CONFIG_BCM43XX_DEBUG 8 + 9 + #include <linux/list.h> 10 + #include <asm/semaphore.h> 11 + 12 + struct dentry; 13 + 14 + /* limited by the size of the "really_big_buffer" */ 15 + #define BCM43xx_NR_LOGGED_XMITSTATUS 100 16 + 17 + struct bcm43xx_dfsentry { 18 + struct dentry *subdir; 19 + struct dentry *dentry_devinfo; 20 + struct dentry *dentry_spromdump; 21 + struct dentry *dentry_tsf; 22 + struct dentry *dentry_txstat; 23 + 24 + struct bcm43xx_private *bcm; 25 + 26 + /* saved xmitstatus. */ 27 + struct bcm43xx_xmitstatus *xmitstatus_buffer; 28 + int xmitstatus_ptr; 29 + int xmitstatus_cnt; 30 + /* We need a seperate buffer while printing to avoid 31 + * concurrency issues. (New xmitstatus can arrive 32 + * while we are printing). 33 + */ 34 + struct bcm43xx_xmitstatus *xmitstatus_print_buffer; 35 + int saved_xmitstatus_ptr; 36 + int saved_xmitstatus_cnt; 37 + int xmitstatus_printing; 38 + }; 39 + 40 + struct bcm43xx_debugfs { 41 + struct dentry *root; 42 + struct dentry *dentry_driverinfo; 43 + }; 44 + 45 + void bcm43xx_debugfs_init(void); 46 + void bcm43xx_debugfs_exit(void); 47 + void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm); 48 + void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm); 49 + void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, 50 + struct bcm43xx_xmitstatus *status); 51 + 52 + /* Debug helper: Dump binary data through printk. */ 53 + void bcm43xx_printk_dump(const char *data, 54 + size_t size, 55 + const char *description); 56 + /* Debug helper: Dump bitwise binary data through printk. */ 57 + void bcm43xx_printk_bitdump(const unsigned char *data, 58 + size_t bytes, int msb_to_lsb, 59 + const char *description); 60 + #define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \ 61 + do { \ 62 + bcm43xx_printk_bitdump((const unsigned char *)(pointer), \ 63 + sizeof(*(pointer)), \ 64 + (msb_to_lsb), \ 65 + (description)); \ 66 + } while (0) 67 + 68 + #else /* CONFIG_BCM43XX_DEBUG*/ 69 + 70 + static inline 71 + void bcm43xx_debugfs_init(void) { } 72 + static inline 73 + void bcm43xx_debugfs_exit(void) { } 74 + static inline 75 + void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { } 76 + static inline 77 + void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { } 78 + static inline 79 + void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, 80 + struct bcm43xx_xmitstatus *status) { } 81 + 82 + static inline 83 + void bcm43xx_printk_dump(const char *data, 84 + size_t size, 85 + const char *description) 86 + { 87 + } 88 + static inline 89 + void bcm43xx_printk_bitdump(const unsigned char *data, 90 + size_t bytes, int msb_to_lsb, 91 + const char *description) 92 + { 93 + } 94 + #define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0) 95 + 96 + #endif /* CONFIG_BCM43XX_DEBUG*/ 97 + 98 + /* Ugly helper macros to make incomplete code more verbose on runtime */ 99 + #ifdef TODO 100 + # undef TODO 101 + #endif 102 + #define TODO() \ 103 + do { \ 104 + printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \ 105 + __FUNCTION__, __FILE__, __LINE__); \ 106 + } while (0) 107 + 108 + #ifdef FIXME 109 + # undef FIXME 110 + #endif 111 + #define FIXME() \ 112 + do { \ 113 + printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \ 114 + __FUNCTION__, __FILE__, __LINE__); \ 115 + } while (0) 116 + 117 + #endif /* BCM43xx_DEBUGFS_H_ */
+968
drivers/net/wireless/bcm43xx/bcm43xx_dma.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + DMA ringbuffer and descriptor allocation/management 6 + 7 + Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de> 8 + 9 + Some code in this file is derived from the b44.c driver 10 + Copyright (C) 2002 David S. Miller 11 + Copyright (C) Pekka Pietikainen 12 + 13 + This program is free software; you can redistribute it and/or modify 14 + it under the terms of the GNU General Public License as published by 15 + the Free Software Foundation; either version 2 of the License, or 16 + (at your option) any later version. 17 + 18 + This program is distributed in the hope that it will be useful, 19 + but WITHOUT ANY WARRANTY; without even the implied warranty of 20 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 + GNU General Public License for more details. 22 + 23 + You should have received a copy of the GNU General Public License 24 + along with this program; see the file COPYING. If not, write to 25 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 26 + Boston, MA 02110-1301, USA. 27 + 28 + */ 29 + 30 + #include "bcm43xx.h" 31 + #include "bcm43xx_dma.h" 32 + #include "bcm43xx_main.h" 33 + #include "bcm43xx_debugfs.h" 34 + #include "bcm43xx_power.h" 35 + #include "bcm43xx_xmit.h" 36 + 37 + #include <linux/dma-mapping.h> 38 + #include <linux/pci.h> 39 + #include <linux/delay.h> 40 + #include <linux/skbuff.h> 41 + 42 + 43 + static inline int free_slots(struct bcm43xx_dmaring *ring) 44 + { 45 + return (ring->nr_slots - ring->used_slots); 46 + } 47 + 48 + static inline int next_slot(struct bcm43xx_dmaring *ring, int slot) 49 + { 50 + assert(slot >= -1 && slot <= ring->nr_slots - 1); 51 + if (slot == ring->nr_slots - 1) 52 + return 0; 53 + return slot + 1; 54 + } 55 + 56 + static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot) 57 + { 58 + assert(slot >= 0 && slot <= ring->nr_slots - 1); 59 + if (slot == 0) 60 + return ring->nr_slots - 1; 61 + return slot - 1; 62 + } 63 + 64 + /* Request a slot for usage. */ 65 + static inline 66 + int request_slot(struct bcm43xx_dmaring *ring) 67 + { 68 + int slot; 69 + 70 + assert(ring->tx); 71 + assert(!ring->suspended); 72 + assert(free_slots(ring) != 0); 73 + 74 + slot = next_slot(ring, ring->current_slot); 75 + ring->current_slot = slot; 76 + ring->used_slots++; 77 + 78 + /* Check the number of available slots and suspend TX, 79 + * if we are running low on free slots. 80 + */ 81 + if (unlikely(free_slots(ring) < ring->suspend_mark)) { 82 + netif_stop_queue(ring->bcm->net_dev); 83 + ring->suspended = 1; 84 + } 85 + #ifdef CONFIG_BCM43XX_DEBUG 86 + if (ring->used_slots > ring->max_used_slots) 87 + ring->max_used_slots = ring->used_slots; 88 + #endif /* CONFIG_BCM43XX_DEBUG*/ 89 + 90 + return slot; 91 + } 92 + 93 + /* Return a slot to the free slots. */ 94 + static inline 95 + void return_slot(struct bcm43xx_dmaring *ring, int slot) 96 + { 97 + assert(ring->tx); 98 + 99 + ring->used_slots--; 100 + 101 + /* Check if TX is suspended and check if we have 102 + * enough free slots to resume it again. 103 + */ 104 + if (unlikely(ring->suspended)) { 105 + if (free_slots(ring) >= ring->resume_mark) { 106 + ring->suspended = 0; 107 + netif_wake_queue(ring->bcm->net_dev); 108 + } 109 + } 110 + } 111 + 112 + static inline 113 + dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, 114 + unsigned char *buf, 115 + size_t len, 116 + int tx) 117 + { 118 + dma_addr_t dmaaddr; 119 + 120 + if (tx) { 121 + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, 122 + buf, len, 123 + DMA_TO_DEVICE); 124 + } else { 125 + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, 126 + buf, len, 127 + DMA_FROM_DEVICE); 128 + } 129 + 130 + return dmaaddr; 131 + } 132 + 133 + static inline 134 + void unmap_descbuffer(struct bcm43xx_dmaring *ring, 135 + dma_addr_t addr, 136 + size_t len, 137 + int tx) 138 + { 139 + if (tx) { 140 + dma_unmap_single(&ring->bcm->pci_dev->dev, 141 + addr, len, 142 + DMA_TO_DEVICE); 143 + } else { 144 + dma_unmap_single(&ring->bcm->pci_dev->dev, 145 + addr, len, 146 + DMA_FROM_DEVICE); 147 + } 148 + } 149 + 150 + static inline 151 + void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring, 152 + dma_addr_t addr, 153 + size_t len) 154 + { 155 + assert(!ring->tx); 156 + 157 + dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev, 158 + addr, len, DMA_FROM_DEVICE); 159 + } 160 + 161 + static inline 162 + void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, 163 + dma_addr_t addr, 164 + size_t len) 165 + { 166 + assert(!ring->tx); 167 + 168 + dma_sync_single_for_device(&ring->bcm->pci_dev->dev, 169 + addr, len, DMA_FROM_DEVICE); 170 + } 171 + 172 + /* Unmap and free a descriptor buffer. */ 173 + static inline 174 + void free_descriptor_buffer(struct bcm43xx_dmaring *ring, 175 + struct bcm43xx_dmadesc *desc, 176 + struct bcm43xx_dmadesc_meta *meta, 177 + int irq_context) 178 + { 179 + assert(meta->skb); 180 + if (irq_context) 181 + dev_kfree_skb_irq(meta->skb); 182 + else 183 + dev_kfree_skb(meta->skb); 184 + meta->skb = NULL; 185 + } 186 + 187 + static int alloc_ringmemory(struct bcm43xx_dmaring *ring) 188 + { 189 + struct device *dev = &(ring->bcm->pci_dev->dev); 190 + 191 + ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, 192 + &(ring->dmabase), GFP_KERNEL); 193 + if (!ring->vbase) { 194 + printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); 195 + return -ENOMEM; 196 + } 197 + if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { 198 + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " 199 + "(0x%08x, len: %lu)\n", 200 + ring->dmabase, BCM43xx_DMA_RINGMEMSIZE); 201 + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, 202 + ring->vbase, ring->dmabase); 203 + return -ENOMEM; 204 + } 205 + assert(!(ring->dmabase & 0x000003FF)); 206 + memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE); 207 + 208 + return 0; 209 + } 210 + 211 + static void free_ringmemory(struct bcm43xx_dmaring *ring) 212 + { 213 + struct device *dev = &(ring->bcm->pci_dev->dev); 214 + 215 + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, 216 + ring->vbase, ring->dmabase); 217 + } 218 + 219 + /* Reset the RX DMA channel */ 220 + int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, 221 + u16 mmio_base) 222 + { 223 + int i; 224 + u32 value; 225 + 226 + bcm43xx_write32(bcm, 227 + mmio_base + BCM43xx_DMA_RX_CONTROL, 228 + 0x00000000); 229 + for (i = 0; i < 1000; i++) { 230 + value = bcm43xx_read32(bcm, 231 + mmio_base + BCM43xx_DMA_RX_STATUS); 232 + value &= BCM43xx_DMA_RXSTAT_STAT_MASK; 233 + if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) { 234 + i = -1; 235 + break; 236 + } 237 + udelay(10); 238 + } 239 + if (i != -1) { 240 + printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n"); 241 + return -ENODEV; 242 + } 243 + 244 + return 0; 245 + } 246 + 247 + /* Reset the RX DMA channel */ 248 + int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, 249 + u16 mmio_base) 250 + { 251 + int i; 252 + u32 value; 253 + 254 + for (i = 0; i < 1000; i++) { 255 + value = bcm43xx_read32(bcm, 256 + mmio_base + BCM43xx_DMA_TX_STATUS); 257 + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; 258 + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED || 259 + value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT || 260 + value == BCM43xx_DMA_TXSTAT_STAT_STOPPED) 261 + break; 262 + udelay(10); 263 + } 264 + bcm43xx_write32(bcm, 265 + mmio_base + BCM43xx_DMA_TX_CONTROL, 266 + 0x00000000); 267 + for (i = 0; i < 1000; i++) { 268 + value = bcm43xx_read32(bcm, 269 + mmio_base + BCM43xx_DMA_TX_STATUS); 270 + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; 271 + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) { 272 + i = -1; 273 + break; 274 + } 275 + udelay(10); 276 + } 277 + if (i != -1) { 278 + printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n"); 279 + return -ENODEV; 280 + } 281 + /* ensure the reset is completed. */ 282 + udelay(300); 283 + 284 + return 0; 285 + } 286 + 287 + static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, 288 + struct bcm43xx_dmadesc *desc, 289 + struct bcm43xx_dmadesc_meta *meta, 290 + gfp_t gfp_flags) 291 + { 292 + struct bcm43xx_rxhdr *rxhdr; 293 + dma_addr_t dmaaddr; 294 + u32 desc_addr; 295 + u32 desc_ctl; 296 + const int slot = (int)(desc - ring->vbase); 297 + struct sk_buff *skb; 298 + 299 + assert(slot >= 0 && slot < ring->nr_slots); 300 + assert(!ring->tx); 301 + 302 + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); 303 + if (unlikely(!skb)) 304 + return -ENOMEM; 305 + dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); 306 + if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) { 307 + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); 308 + dev_kfree_skb_any(skb); 309 + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " 310 + "(0x%08x, len: %u)\n", 311 + dmaaddr, ring->rx_buffersize); 312 + return -ENOMEM; 313 + } 314 + meta->skb = skb; 315 + meta->dmaaddr = dmaaddr; 316 + skb->dev = ring->bcm->net_dev; 317 + desc_addr = (u32)(dmaaddr + ring->memoffset); 318 + desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & 319 + (u32)(ring->rx_buffersize - ring->frameoffset)); 320 + if (slot == ring->nr_slots - 1) 321 + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; 322 + set_desc_addr(desc, desc_addr); 323 + set_desc_ctl(desc, desc_ctl); 324 + 325 + rxhdr = (struct bcm43xx_rxhdr *)(skb->data); 326 + rxhdr->frame_length = 0; 327 + rxhdr->flags1 = 0; 328 + 329 + return 0; 330 + } 331 + 332 + /* Allocate the initial descbuffers. 333 + * This is used for an RX ring only. 334 + */ 335 + static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) 336 + { 337 + int i, err = -ENOMEM; 338 + struct bcm43xx_dmadesc *desc; 339 + struct bcm43xx_dmadesc_meta *meta; 340 + 341 + for (i = 0; i < ring->nr_slots; i++) { 342 + desc = ring->vbase + i; 343 + meta = ring->meta + i; 344 + 345 + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); 346 + if (err) 347 + goto err_unwind; 348 + } 349 + ring->used_slots = ring->nr_slots; 350 + err = 0; 351 + out: 352 + return err; 353 + 354 + err_unwind: 355 + for (i--; i >= 0; i--) { 356 + desc = ring->vbase + i; 357 + meta = ring->meta + i; 358 + 359 + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); 360 + dev_kfree_skb(meta->skb); 361 + } 362 + goto out; 363 + } 364 + 365 + /* Do initial setup of the DMA controller. 366 + * Reset the controller, write the ring busaddress 367 + * and switch the "enable" bit on. 368 + */ 369 + static int dmacontroller_setup(struct bcm43xx_dmaring *ring) 370 + { 371 + int err = 0; 372 + u32 value; 373 + 374 + if (ring->tx) { 375 + /* Set Transmit Control register to "transmit enable" */ 376 + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, 377 + BCM43xx_DMA_TXCTRL_ENABLE); 378 + /* Set Transmit Descriptor ring address. */ 379 + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 380 + ring->dmabase + ring->memoffset); 381 + } else { 382 + err = alloc_initial_descbuffers(ring); 383 + if (err) 384 + goto out; 385 + /* Set Receive Control "receive enable" and frame offset */ 386 + value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT); 387 + value |= BCM43xx_DMA_RXCTRL_ENABLE; 388 + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value); 389 + /* Set Receive Descriptor ring address. */ 390 + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 391 + ring->dmabase + ring->memoffset); 392 + /* Init the descriptor pointer. */ 393 + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200); 394 + } 395 + 396 + out: 397 + return err; 398 + } 399 + 400 + /* Shutdown the DMA controller. */ 401 + static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) 402 + { 403 + if (ring->tx) { 404 + bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); 405 + /* Zero out Transmit Descriptor ring address. */ 406 + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0); 407 + } else { 408 + bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); 409 + /* Zero out Receive Descriptor ring address. */ 410 + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0); 411 + } 412 + } 413 + 414 + static void free_all_descbuffers(struct bcm43xx_dmaring *ring) 415 + { 416 + struct bcm43xx_dmadesc *desc; 417 + struct bcm43xx_dmadesc_meta *meta; 418 + int i; 419 + 420 + if (!ring->used_slots) 421 + return; 422 + for (i = 0; i < ring->nr_slots; i++) { 423 + desc = ring->vbase + i; 424 + meta = ring->meta + i; 425 + 426 + if (!meta->skb) { 427 + assert(ring->tx); 428 + continue; 429 + } 430 + if (ring->tx) { 431 + unmap_descbuffer(ring, meta->dmaaddr, 432 + meta->skb->len, 1); 433 + } else { 434 + unmap_descbuffer(ring, meta->dmaaddr, 435 + ring->rx_buffersize, 0); 436 + } 437 + free_descriptor_buffer(ring, desc, meta, 0); 438 + } 439 + } 440 + 441 + /* Main initialization function. */ 442 + static 443 + struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, 444 + u16 dma_controller_base, 445 + int nr_descriptor_slots, 446 + int tx) 447 + { 448 + struct bcm43xx_dmaring *ring; 449 + int err; 450 + 451 + ring = kzalloc(sizeof(*ring), GFP_KERNEL); 452 + if (!ring) 453 + goto out; 454 + 455 + ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots, 456 + GFP_KERNEL); 457 + if (!ring->meta) 458 + goto err_kfree_ring; 459 + 460 + ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET; 461 + #ifdef CONFIG_BCM947XX 462 + if (bcm->pci_dev->bus->number == 0) 463 + ring->memoffset = 0; 464 + #endif 465 + 466 + ring->bcm = bcm; 467 + ring->nr_slots = nr_descriptor_slots; 468 + ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; 469 + ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100; 470 + assert(ring->suspend_mark < ring->resume_mark); 471 + ring->mmio_base = dma_controller_base; 472 + if (tx) { 473 + ring->tx = 1; 474 + ring->current_slot = -1; 475 + } else { 476 + switch (dma_controller_base) { 477 + case BCM43xx_MMIO_DMA1_BASE: 478 + ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE; 479 + ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET; 480 + break; 481 + case BCM43xx_MMIO_DMA4_BASE: 482 + ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE; 483 + ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET; 484 + break; 485 + default: 486 + assert(0); 487 + } 488 + } 489 + 490 + err = alloc_ringmemory(ring); 491 + if (err) 492 + goto err_kfree_meta; 493 + err = dmacontroller_setup(ring); 494 + if (err) 495 + goto err_free_ringmemory; 496 + 497 + out: 498 + return ring; 499 + 500 + err_free_ringmemory: 501 + free_ringmemory(ring); 502 + err_kfree_meta: 503 + kfree(ring->meta); 504 + err_kfree_ring: 505 + kfree(ring); 506 + ring = NULL; 507 + goto out; 508 + } 509 + 510 + /* Main cleanup function. */ 511 + static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) 512 + { 513 + if (!ring) 514 + return; 515 + 516 + dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n", 517 + ring->mmio_base, 518 + (ring->tx) ? "TX" : "RX", 519 + ring->max_used_slots, ring->nr_slots); 520 + /* Device IRQs are disabled prior entering this function, 521 + * so no need to take care of concurrency with rx handler stuff. 522 + */ 523 + dmacontroller_cleanup(ring); 524 + free_all_descbuffers(ring); 525 + free_ringmemory(ring); 526 + 527 + kfree(ring->meta); 528 + kfree(ring); 529 + } 530 + 531 + void bcm43xx_dma_free(struct bcm43xx_private *bcm) 532 + { 533 + struct bcm43xx_dma *dma; 534 + 535 + if (bcm43xx_using_pio(bcm)) 536 + return; 537 + dma = bcm43xx_current_dma(bcm); 538 + 539 + bcm43xx_destroy_dmaring(dma->rx_ring1); 540 + dma->rx_ring1 = NULL; 541 + bcm43xx_destroy_dmaring(dma->rx_ring0); 542 + dma->rx_ring0 = NULL; 543 + bcm43xx_destroy_dmaring(dma->tx_ring3); 544 + dma->tx_ring3 = NULL; 545 + bcm43xx_destroy_dmaring(dma->tx_ring2); 546 + dma->tx_ring2 = NULL; 547 + bcm43xx_destroy_dmaring(dma->tx_ring1); 548 + dma->tx_ring1 = NULL; 549 + bcm43xx_destroy_dmaring(dma->tx_ring0); 550 + dma->tx_ring0 = NULL; 551 + } 552 + 553 + int bcm43xx_dma_init(struct bcm43xx_private *bcm) 554 + { 555 + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); 556 + struct bcm43xx_dmaring *ring; 557 + int err = -ENOMEM; 558 + 559 + /* setup TX DMA channels. */ 560 + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, 561 + BCM43xx_TXRING_SLOTS, 1); 562 + if (!ring) 563 + goto out; 564 + dma->tx_ring0 = ring; 565 + 566 + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE, 567 + BCM43xx_TXRING_SLOTS, 1); 568 + if (!ring) 569 + goto err_destroy_tx0; 570 + dma->tx_ring1 = ring; 571 + 572 + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE, 573 + BCM43xx_TXRING_SLOTS, 1); 574 + if (!ring) 575 + goto err_destroy_tx1; 576 + dma->tx_ring2 = ring; 577 + 578 + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, 579 + BCM43xx_TXRING_SLOTS, 1); 580 + if (!ring) 581 + goto err_destroy_tx2; 582 + dma->tx_ring3 = ring; 583 + 584 + /* setup RX DMA channels. */ 585 + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, 586 + BCM43xx_RXRING_SLOTS, 0); 587 + if (!ring) 588 + goto err_destroy_tx3; 589 + dma->rx_ring0 = ring; 590 + 591 + if (bcm->current_core->rev < 5) { 592 + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, 593 + BCM43xx_RXRING_SLOTS, 0); 594 + if (!ring) 595 + goto err_destroy_rx0; 596 + dma->rx_ring1 = ring; 597 + } 598 + 599 + dprintk(KERN_INFO PFX "DMA initialized\n"); 600 + err = 0; 601 + out: 602 + return err; 603 + 604 + err_destroy_rx0: 605 + bcm43xx_destroy_dmaring(dma->rx_ring0); 606 + dma->rx_ring0 = NULL; 607 + err_destroy_tx3: 608 + bcm43xx_destroy_dmaring(dma->tx_ring3); 609 + dma->tx_ring3 = NULL; 610 + err_destroy_tx2: 611 + bcm43xx_destroy_dmaring(dma->tx_ring2); 612 + dma->tx_ring2 = NULL; 613 + err_destroy_tx1: 614 + bcm43xx_destroy_dmaring(dma->tx_ring1); 615 + dma->tx_ring1 = NULL; 616 + err_destroy_tx0: 617 + bcm43xx_destroy_dmaring(dma->tx_ring0); 618 + dma->tx_ring0 = NULL; 619 + goto out; 620 + } 621 + 622 + /* Generate a cookie for the TX header. */ 623 + static u16 generate_cookie(struct bcm43xx_dmaring *ring, 624 + int slot) 625 + { 626 + u16 cookie = 0x0000; 627 + 628 + /* Use the upper 4 bits of the cookie as 629 + * DMA controller ID and store the slot number 630 + * in the lower 12 bits 631 + */ 632 + switch (ring->mmio_base) { 633 + default: 634 + assert(0); 635 + case BCM43xx_MMIO_DMA1_BASE: 636 + break; 637 + case BCM43xx_MMIO_DMA2_BASE: 638 + cookie = 0x1000; 639 + break; 640 + case BCM43xx_MMIO_DMA3_BASE: 641 + cookie = 0x2000; 642 + break; 643 + case BCM43xx_MMIO_DMA4_BASE: 644 + cookie = 0x3000; 645 + break; 646 + } 647 + assert(((u16)slot & 0xF000) == 0x0000); 648 + cookie |= (u16)slot; 649 + 650 + return cookie; 651 + } 652 + 653 + /* Inspect a cookie and find out to which controller/slot it belongs. */ 654 + static 655 + struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, 656 + u16 cookie, int *slot) 657 + { 658 + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); 659 + struct bcm43xx_dmaring *ring = NULL; 660 + 661 + switch (cookie & 0xF000) { 662 + case 0x0000: 663 + ring = dma->tx_ring0; 664 + break; 665 + case 0x1000: 666 + ring = dma->tx_ring1; 667 + break; 668 + case 0x2000: 669 + ring = dma->tx_ring2; 670 + break; 671 + case 0x3000: 672 + ring = dma->tx_ring3; 673 + break; 674 + default: 675 + assert(0); 676 + } 677 + *slot = (cookie & 0x0FFF); 678 + assert(*slot >= 0 && *slot < ring->nr_slots); 679 + 680 + return ring; 681 + } 682 + 683 + static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, 684 + int slot) 685 + { 686 + /* Everything is ready to start. Buffers are DMA mapped and 687 + * associated with slots. 688 + * "slot" is the last slot of the new frame we want to transmit. 689 + * Close your seat belts now, please. 690 + */ 691 + wmb(); 692 + slot = next_slot(ring, slot); 693 + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX, 694 + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); 695 + } 696 + 697 + static int dma_tx_fragment(struct bcm43xx_dmaring *ring, 698 + struct sk_buff *skb, 699 + u8 cur_frag) 700 + { 701 + int slot; 702 + struct bcm43xx_dmadesc *desc; 703 + struct bcm43xx_dmadesc_meta *meta; 704 + u32 desc_ctl; 705 + u32 desc_addr; 706 + 707 + assert(skb_shinfo(skb)->nr_frags == 0); 708 + 709 + slot = request_slot(ring); 710 + desc = ring->vbase + slot; 711 + meta = ring->meta + slot; 712 + 713 + /* Add a device specific TX header. */ 714 + assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); 715 + /* Reserve enough headroom for the device tx header. */ 716 + __skb_push(skb, sizeof(struct bcm43xx_txhdr)); 717 + /* Now calculate and add the tx header. 718 + * The tx header includes the PLCP header. 719 + */ 720 + bcm43xx_generate_txhdr(ring->bcm, 721 + (struct bcm43xx_txhdr *)skb->data, 722 + skb->data + sizeof(struct bcm43xx_txhdr), 723 + skb->len - sizeof(struct bcm43xx_txhdr), 724 + (cur_frag == 0), 725 + generate_cookie(ring, slot)); 726 + 727 + meta->skb = skb; 728 + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); 729 + if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { 730 + return_slot(ring, slot); 731 + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " 732 + "(0x%08x, len: %u)\n", 733 + meta->dmaaddr, skb->len); 734 + return -ENOMEM; 735 + } 736 + 737 + desc_addr = (u32)(meta->dmaaddr + ring->memoffset); 738 + desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND; 739 + desc_ctl |= BCM43xx_DMADTOR_COMPIRQ; 740 + desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK & 741 + (u32)(meta->skb->len - ring->frameoffset)); 742 + if (slot == ring->nr_slots - 1) 743 + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; 744 + 745 + set_desc_ctl(desc, desc_ctl); 746 + set_desc_addr(desc, desc_addr); 747 + /* Now transfer the whole frame. */ 748 + dmacontroller_poke_tx(ring, slot); 749 + 750 + return 0; 751 + } 752 + 753 + int bcm43xx_dma_tx(struct bcm43xx_private *bcm, 754 + struct ieee80211_txb *txb) 755 + { 756 + /* We just received a packet from the kernel network subsystem. 757 + * Add headers and DMA map the memory. Poke 758 + * the device to send the stuff. 759 + * Note that this is called from atomic context. 760 + */ 761 + struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1; 762 + u8 i; 763 + struct sk_buff *skb; 764 + 765 + assert(ring->tx); 766 + if (unlikely(free_slots(ring) < txb->nr_frags)) { 767 + /* The queue should be stopped, 768 + * if we are low on free slots. 769 + * If this ever triggers, we have to lower the suspend_mark. 770 + */ 771 + dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n"); 772 + return -ENOMEM; 773 + } 774 + 775 + for (i = 0; i < txb->nr_frags; i++) { 776 + skb = txb->fragments[i]; 777 + /* Take skb from ieee80211_txb_free */ 778 + txb->fragments[i] = NULL; 779 + dma_tx_fragment(ring, skb, i); 780 + //TODO: handle failure of dma_tx_fragment 781 + } 782 + ieee80211_txb_free(txb); 783 + 784 + return 0; 785 + } 786 + 787 + void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, 788 + struct bcm43xx_xmitstatus *status) 789 + { 790 + struct bcm43xx_dmaring *ring; 791 + struct bcm43xx_dmadesc *desc; 792 + struct bcm43xx_dmadesc_meta *meta; 793 + int is_last_fragment; 794 + int slot; 795 + 796 + ring = parse_cookie(bcm, status->cookie, &slot); 797 + assert(ring); 798 + assert(ring->tx); 799 + assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART); 800 + while (1) { 801 + assert(slot >= 0 && slot < ring->nr_slots); 802 + desc = ring->vbase + slot; 803 + meta = ring->meta + slot; 804 + 805 + is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND); 806 + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); 807 + free_descriptor_buffer(ring, desc, meta, 1); 808 + /* Everything belonging to the slot is unmapped 809 + * and freed, so we can return it. 810 + */ 811 + return_slot(ring, slot); 812 + 813 + if (is_last_fragment) 814 + break; 815 + slot = next_slot(ring, slot); 816 + } 817 + bcm->stats.last_tx = jiffies; 818 + } 819 + 820 + static void dma_rx(struct bcm43xx_dmaring *ring, 821 + int *slot) 822 + { 823 + struct bcm43xx_dmadesc *desc; 824 + struct bcm43xx_dmadesc_meta *meta; 825 + struct bcm43xx_rxhdr *rxhdr; 826 + struct sk_buff *skb; 827 + u16 len; 828 + int err; 829 + dma_addr_t dmaaddr; 830 + 831 + desc = ring->vbase + *slot; 832 + meta = ring->meta + *slot; 833 + 834 + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); 835 + skb = meta->skb; 836 + 837 + if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) { 838 + /* We received an xmit status. */ 839 + struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data; 840 + struct bcm43xx_xmitstatus stat; 841 + 842 + stat.cookie = le16_to_cpu(hw->cookie); 843 + stat.flags = hw->flags; 844 + stat.cnt1 = hw->cnt1; 845 + stat.cnt2 = hw->cnt2; 846 + stat.seq = le16_to_cpu(hw->seq); 847 + stat.unknown = le16_to_cpu(hw->unknown); 848 + 849 + bcm43xx_debugfs_log_txstat(ring->bcm, &stat); 850 + bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat); 851 + /* recycle the descriptor buffer. */ 852 + sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize); 853 + 854 + return; 855 + } 856 + rxhdr = (struct bcm43xx_rxhdr *)skb->data; 857 + len = le16_to_cpu(rxhdr->frame_length); 858 + if (len == 0) { 859 + int i = 0; 860 + 861 + do { 862 + udelay(2); 863 + barrier(); 864 + len = le16_to_cpu(rxhdr->frame_length); 865 + } while (len == 0 && i++ < 5); 866 + if (unlikely(len == 0)) { 867 + /* recycle the descriptor buffer. */ 868 + sync_descbuffer_for_device(ring, meta->dmaaddr, 869 + ring->rx_buffersize); 870 + goto drop; 871 + } 872 + } 873 + if (unlikely(len > ring->rx_buffersize)) { 874 + /* The data did not fit into one descriptor buffer 875 + * and is split over multiple buffers. 876 + * This should never happen, as we try to allocate buffers 877 + * big enough. So simply ignore this packet. 878 + */ 879 + int cnt = 0; 880 + s32 tmp = len; 881 + 882 + while (1) { 883 + desc = ring->vbase + *slot; 884 + meta = ring->meta + *slot; 885 + /* recycle the descriptor buffer. */ 886 + sync_descbuffer_for_device(ring, meta->dmaaddr, 887 + ring->rx_buffersize); 888 + *slot = next_slot(ring, *slot); 889 + cnt++; 890 + tmp -= ring->rx_buffersize; 891 + if (tmp <= 0) 892 + break; 893 + } 894 + printkl(KERN_ERR PFX "DMA RX buffer too small " 895 + "(len: %u, buffer: %u, nr-dropped: %d)\n", 896 + len, ring->rx_buffersize, cnt); 897 + goto drop; 898 + } 899 + len -= IEEE80211_FCS_LEN; 900 + 901 + dmaaddr = meta->dmaaddr; 902 + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); 903 + if (unlikely(err)) { 904 + dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n"); 905 + sync_descbuffer_for_device(ring, dmaaddr, 906 + ring->rx_buffersize); 907 + goto drop; 908 + } 909 + 910 + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); 911 + skb_put(skb, len + ring->frameoffset); 912 + skb_pull(skb, ring->frameoffset); 913 + 914 + err = bcm43xx_rx(ring->bcm, skb, rxhdr); 915 + if (err) { 916 + dev_kfree_skb_irq(skb); 917 + goto drop; 918 + } 919 + 920 + drop: 921 + return; 922 + } 923 + 924 + void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) 925 + { 926 + u32 status; 927 + u16 descptr; 928 + int slot, current_slot; 929 + #ifdef CONFIG_BCM43XX_DEBUG 930 + int used_slots = 0; 931 + #endif 932 + 933 + assert(!ring->tx); 934 + status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS); 935 + descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); 936 + current_slot = descptr / sizeof(struct bcm43xx_dmadesc); 937 + assert(current_slot >= 0 && current_slot < ring->nr_slots); 938 + 939 + slot = ring->current_slot; 940 + for ( ; slot != current_slot; slot = next_slot(ring, slot)) { 941 + dma_rx(ring, &slot); 942 + #ifdef CONFIG_BCM43XX_DEBUG 943 + if (++used_slots > ring->max_used_slots) 944 + ring->max_used_slots = used_slots; 945 + #endif 946 + } 947 + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 948 + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); 949 + ring->current_slot = slot; 950 + } 951 + 952 + void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) 953 + { 954 + assert(ring->tx); 955 + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1); 956 + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, 957 + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) 958 + | BCM43xx_DMA_TXCTRL_SUSPEND); 959 + } 960 + 961 + void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) 962 + { 963 + assert(ring->tx); 964 + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, 965 + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) 966 + & ~BCM43xx_DMA_TXCTRL_SUSPEND); 967 + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); 968 + }
+218
drivers/net/wireless/bcm43xx/bcm43xx_dma.h
··· 1 + #ifndef BCM43xx_DMA_H_ 2 + #define BCM43xx_DMA_H_ 3 + 4 + #include <linux/list.h> 5 + #include <linux/spinlock.h> 6 + #include <linux/workqueue.h> 7 + #include <linux/linkage.h> 8 + #include <asm/atomic.h> 9 + 10 + 11 + /* DMA-Interrupt reasons. */ 12 + #define BCM43xx_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ 13 + | (1 << 14) | (1 << 15)) 14 + #define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13) 15 + #define BCM43xx_DMAIRQ_RX_DONE (1 << 16) 16 + 17 + /* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */ 18 + #define BCM43xx_DMA_TX_CONTROL 0x00 19 + #define BCM43xx_DMA_TX_DESC_RING 0x04 20 + #define BCM43xx_DMA_TX_DESC_INDEX 0x08 21 + #define BCM43xx_DMA_TX_STATUS 0x0c 22 + #define BCM43xx_DMA_RX_CONTROL 0x10 23 + #define BCM43xx_DMA_RX_DESC_RING 0x14 24 + #define BCM43xx_DMA_RX_DESC_INDEX 0x18 25 + #define BCM43xx_DMA_RX_STATUS 0x1c 26 + 27 + /* DMA controller channel control word values. */ 28 + #define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0) 29 + #define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1) 30 + #define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2) 31 + #define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4) 32 + #define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0) 33 + #define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe 34 + #define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1 35 + #define BCM43xx_DMA_RXCTRL_PIO (1 << 8) 36 + /* DMA controller channel status word values. */ 37 + #define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff 38 + #define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000 39 + #define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000 40 + #define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000 41 + #define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000 42 + #define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000 43 + #define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000 44 + #define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000 45 + #define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20) 46 + #define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff 47 + #define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000 48 + #define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000 49 + #define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000 50 + #define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000 51 + #define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000 52 + #define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000 53 + #define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000 54 + 55 + /* DMA descriptor control field values. */ 56 + #define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff 57 + #define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */ 58 + #define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */ 59 + #define BCM43xx_DMADTOR_FRAMEEND (1 << 30) 60 + #define BCM43xx_DMADTOR_FRAMESTART (1 << 31) 61 + 62 + /* Misc DMA constants */ 63 + #define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE 64 + #define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF 65 + #define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30) 66 + #define BCM43xx_DMA1_RX_FRAMEOFFSET 30 67 + #define BCM43xx_DMA4_RX_FRAMEOFFSET 0 68 + 69 + /* DMA engine tuning knobs */ 70 + #define BCM43xx_TXRING_SLOTS 512 71 + #define BCM43xx_RXRING_SLOTS 64 72 + #define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100) 73 + #define BCM43xx_DMA4_RXBUFFERSIZE 16 74 + /* Suspend the tx queue, if less than this percent slots are free. */ 75 + #define BCM43xx_TXSUSPEND_PERCENT 20 76 + /* Resume the tx queue, if more than this percent slots are free. */ 77 + #define BCM43xx_TXRESUME_PERCENT 50 78 + 79 + 80 + 81 + #ifdef CONFIG_BCM43XX_DMA 82 + 83 + 84 + struct sk_buff; 85 + struct bcm43xx_private; 86 + struct bcm43xx_xmitstatus; 87 + 88 + 89 + struct bcm43xx_dmadesc { 90 + __le32 _control; 91 + __le32 _address; 92 + } __attribute__((__packed__)); 93 + 94 + /* Macros to access the bcm43xx_dmadesc struct */ 95 + #define get_desc_ctl(desc) le32_to_cpu((desc)->_control) 96 + #define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0) 97 + #define get_desc_addr(desc) le32_to_cpu((desc)->_address) 98 + #define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0) 99 + 100 + struct bcm43xx_dmadesc_meta { 101 + /* The kernel DMA-able buffer. */ 102 + struct sk_buff *skb; 103 + /* DMA base bus-address of the descriptor buffer. */ 104 + dma_addr_t dmaaddr; 105 + }; 106 + 107 + struct bcm43xx_dmaring { 108 + struct bcm43xx_private *bcm; 109 + /* Kernel virtual base address of the ring memory. */ 110 + struct bcm43xx_dmadesc *vbase; 111 + /* DMA memory offset */ 112 + dma_addr_t memoffset; 113 + /* (Unadjusted) DMA base bus-address of the ring memory. */ 114 + dma_addr_t dmabase; 115 + /* Meta data about all descriptors. */ 116 + struct bcm43xx_dmadesc_meta *meta; 117 + /* Number of descriptor slots in the ring. */ 118 + int nr_slots; 119 + /* Number of used descriptor slots. */ 120 + int used_slots; 121 + /* Currently used slot in the ring. */ 122 + int current_slot; 123 + /* Marks to suspend/resume the queue. */ 124 + int suspend_mark; 125 + int resume_mark; 126 + /* Frameoffset in octets. */ 127 + u32 frameoffset; 128 + /* Descriptor buffer size. */ 129 + u16 rx_buffersize; 130 + /* The MMIO base register of the DMA controller, this 131 + * ring is posted to. 132 + */ 133 + u16 mmio_base; 134 + u8 tx:1, /* TRUE, if this is a TX ring. */ 135 + suspended:1; /* TRUE, if transfers are suspended on this ring. */ 136 + #ifdef CONFIG_BCM43XX_DEBUG 137 + /* Maximum number of used slots. */ 138 + int max_used_slots; 139 + #endif /* CONFIG_BCM43XX_DEBUG*/ 140 + }; 141 + 142 + 143 + static inline 144 + u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring, 145 + u16 offset) 146 + { 147 + return bcm43xx_read32(ring->bcm, ring->mmio_base + offset); 148 + } 149 + 150 + static inline 151 + void bcm43xx_dma_write(struct bcm43xx_dmaring *ring, 152 + u16 offset, u32 value) 153 + { 154 + bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value); 155 + } 156 + 157 + 158 + int bcm43xx_dma_init(struct bcm43xx_private *bcm); 159 + void bcm43xx_dma_free(struct bcm43xx_private *bcm); 160 + 161 + int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, 162 + u16 dmacontroller_mmio_base); 163 + int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, 164 + u16 dmacontroller_mmio_base); 165 + 166 + void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring); 167 + void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring); 168 + 169 + void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, 170 + struct bcm43xx_xmitstatus *status); 171 + 172 + int bcm43xx_dma_tx(struct bcm43xx_private *bcm, 173 + struct ieee80211_txb *txb); 174 + void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); 175 + 176 + 177 + #else /* CONFIG_BCM43XX_DMA */ 178 + 179 + 180 + static inline 181 + int bcm43xx_dma_init(struct bcm43xx_private *bcm) 182 + { 183 + return 0; 184 + } 185 + static inline 186 + void bcm43xx_dma_free(struct bcm43xx_private *bcm) 187 + { 188 + } 189 + static inline 190 + int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, 191 + u16 dmacontroller_mmio_base) 192 + { 193 + return 0; 194 + } 195 + static inline 196 + int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, 197 + u16 dmacontroller_mmio_base) 198 + { 199 + return 0; 200 + } 201 + static inline 202 + int bcm43xx_dma_tx(struct bcm43xx_private *bcm, 203 + struct ieee80211_txb *txb) 204 + { 205 + return 0; 206 + } 207 + static inline 208 + void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, 209 + struct bcm43xx_xmitstatus *status) 210 + { 211 + } 212 + static inline 213 + void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) 214 + { 215 + } 216 + 217 + #endif /* CONFIG_BCM43XX_DMA */ 218 + #endif /* BCM43xx_DMA_H_ */
+50
drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + ethtool support 6 + 7 + Copyright (c) 2006 Jason Lunz <lunz@falooley.org> 8 + 9 + Some code in this file is derived from the 8139too.c driver 10 + Copyright (C) 2002 Jeff Garzik 11 + 12 + This program is free software; you can redistribute it and/or modify 13 + it under the terms of the GNU General Public License as published by 14 + the Free Software Foundation; either version 2 of the License, or 15 + (at your option) any later version. 16 + 17 + This program is distributed in the hope that it will be useful, 18 + but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + GNU General Public License for more details. 21 + 22 + You should have received a copy of the GNU General Public License 23 + along with this program; see the file COPYING. If not, write to 24 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 25 + Boston, MA 02110-1301, USA. 26 + 27 + */ 28 + 29 + #include "bcm43xx.h" 30 + #include "bcm43xx_ethtool.h" 31 + 32 + #include <linux/netdevice.h> 33 + #include <linux/pci.h> 34 + #include <linux/string.h> 35 + #include <linux/version.h> 36 + 37 + 38 + static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 39 + { 40 + struct bcm43xx_private *bcm = bcm43xx_priv(dev); 41 + 42 + strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 43 + strncpy(info->version, UTS_RELEASE, sizeof(info->version)); 44 + strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); 45 + } 46 + 47 + struct ethtool_ops bcm43xx_ethtool_ops = { 48 + .get_drvinfo = bcm43xx_get_drvinfo, 49 + .get_link = ethtool_op_get_link, 50 + };
+8
drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
··· 1 + #ifndef BCM43xx_ETHTOOL_H_ 2 + #define BCM43xx_ETHTOOL_H_ 3 + 4 + #include <linux/ethtool.h> 5 + 6 + extern struct ethtool_ops bcm43xx_ethtool_ops; 7 + 8 + #endif /* BCM43xx_ETHTOOL_H_ */
+337
drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + This program is free software; you can redistribute it and/or modify 12 + it under the terms of the GNU General Public License as published by 13 + the Free Software Foundation; either version 2 of the License, or 14 + (at your option) any later version. 15 + 16 + This program is distributed in the hope that it will be useful, 17 + but WITHOUT ANY WARRANTY; without even the implied warranty of 18 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + GNU General Public License for more details. 20 + 21 + You should have received a copy of the GNU General Public License 22 + along with this program; see the file COPYING. If not, write to 23 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 24 + Boston, MA 02110-1301, USA. 25 + 26 + */ 27 + 28 + #include "bcm43xx.h" 29 + #include "bcm43xx_ilt.h" 30 + #include "bcm43xx_phy.h" 31 + 32 + 33 + /**** Initial Internal Lookup Tables ****/ 34 + 35 + const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = { 36 + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ 37 + 0xFED23FFD, 0xFEDF3FFD, 38 + 0xFEEC3FFE, 0xFEF83FFE, 39 + 0xFF053FFE, 0xFF113FFE, 40 + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ 41 + 0xFF373FFF, 0xFF443FFF, 42 + 0xFF503FFF, 0xFF5D3FFF, 43 + 0xFF693FFF, 0xFF763FFF, 44 + 0xFF824000, 0xFF8F4000, /* 16 */ 45 + 0xFF9B4000, 0xFFA84000, 46 + 0xFFB54000, 0xFFC14000, 47 + 0xFFCE4000, 0xFFDA4000, 48 + 0xFFE74000, 0xFFF34000, /* 24 */ 49 + 0x00004000, 0x000D4000, 50 + 0x00194000, 0x00264000, 51 + 0x00324000, 0x003F4000, 52 + 0x004B4000, 0x00584000, /* 32 */ 53 + 0x00654000, 0x00714000, 54 + 0x007E4000, 0x008A3FFF, 55 + 0x00973FFF, 0x00A33FFF, 56 + 0x00B03FFF, 0x00BC3FFF, /* 40 */ 57 + 0x00C93FFF, 0x00D63FFF, 58 + 0x00E23FFE, 0x00EF3FFE, 59 + 0x00FB3FFE, 0x01083FFE, 60 + 0x01143FFE, 0x01213FFD, /* 48 */ 61 + 0x012E3FFD, 0x013A3FFD, 62 + 0x01473FFD, 63 + }; 64 + 65 + const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = { 66 + 0xDB93CB87, 0xD666CF64, /* 0 */ 67 + 0xD1FDD358, 0xCDA6D826, 68 + 0xCA38DD9F, 0xC729E2B4, 69 + 0xC469E88E, 0xC26AEE2B, 70 + 0xC0DEF46C, 0xC073FA62, /* 8 */ 71 + 0xC01D00D5, 0xC0760743, 72 + 0xC1560D1E, 0xC2E51369, 73 + 0xC4ED18FF, 0xC7AC1ED7, 74 + 0xCB2823B2, 0xCEFA28D9, /* 16 */ 75 + 0xD2F62D3F, 0xD7BB3197, 76 + 0xDCE53568, 0xE1FE3875, 77 + 0xE7D13B35, 0xED663D35, 78 + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ 79 + 0x00004000, 0x06723FA7, 80 + 0x0C653EC4, 0x129A3D35, 81 + 0x182F3B35, 0x1E023875, 82 + 0x231B3568, 0x28453197, /* 32 */ 83 + 0x2D0A2D3F, 0x310628D9, 84 + 0x34D823B2, 0x38541ED7, 85 + 0x3B1318FF, 0x3D1B1369, 86 + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ 87 + 0x3FE300D5, 0x3F8DFA62, 88 + 0x3F22F46C, 0x3D96EE2B, 89 + 0x3B97E88E, 0x38D7E2B4, 90 + 0x35C8DD9F, 0x325AD826, /* 48 */ 91 + 0x2E03D358, 0x299ACF64, 92 + 0x246DCB87, 93 + }; 94 + 95 + const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = { 96 + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ 97 + 0x0202, 0x0282, 0x0302, 0x0382, 98 + 0x0402, 0x0482, 0x0502, 0x0582, 99 + 0x05E2, 0x0662, 0x06E2, 0x0762, 100 + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ 101 + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, 102 + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, 103 + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, 104 + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ 105 + 0x1062, 0x10C2, 0x1122, 0x1182, 106 + 0x11E2, 0x1242, 0x12A2, 0x12E2, 107 + 0x1342, 0x13A2, 0x1402, 0x1442, 108 + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ 109 + 0x15E2, 0x1622, 0x1662, 0x16C1, 110 + 0x1701, 0x1741, 0x1781, 0x17E1, 111 + 0x1821, 0x1861, 0x18A1, 0x18E1, 112 + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ 113 + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, 114 + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, 115 + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, 116 + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ 117 + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, 118 + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, 119 + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, 120 + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ 121 + 0x2001, 0x2041, 0x2061, 0x2081, 122 + 0x20A1, 0x20C1, 0x20E1, 0x2101, 123 + 0x2121, 0x2141, 0x2161, 0x2181, 124 + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ 125 + 0x2221, 0x2241, 0x2261, 0x2281, 126 + 0x22A1, 0x22C1, 0x22C1, 0x22E1, 127 + 0x2301, 0x2321, 0x2341, 0x2361, 128 + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ 129 + 0x23E1, 0x23E1, 0x2401, 0x2421, 130 + 0x2441, 0x2441, 0x2461, 0x2481, 131 + 0x2481, 0x24A1, 0x24C1, 0x24C1, 132 + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ 133 + 0x2541, 0x2541, 0x2561, 0x2561, 134 + 0x2581, 0x25A1, 0x25A1, 0x25C1, 135 + 0x25C1, 0x25E1, 0x2601, 0x2601, 136 + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ 137 + 0x2661, 0x2661, 0x2681, 0x2681, 138 + 0x26A1, 0x26A1, 0x26C1, 0x26C1, 139 + 0x26E1, 0x26E1, 0x2701, 0x2701, 140 + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ 141 + 0x2760, 0x2760, 0x2780, 0x2780, 142 + 0x2780, 0x27A0, 0x27A0, 0x27C0, 143 + 0x27C0, 0x27E0, 0x27E0, 0x27E0, 144 + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ 145 + 0x2820, 0x2840, 0x2840, 0x2840, 146 + 0x2860, 0x2860, 0x2880, 0x2880, 147 + 0x2880, 0x28A0, 0x28A0, 0x28A0, 148 + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ 149 + 0x28E0, 0x28E0, 0x2900, 0x2900, 150 + 0x2900, 0x2920, 0x2920, 0x2920, 151 + 0x2940, 0x2940, 0x2940, 0x2960, 152 + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ 153 + 0x2980, 0x2980, 0x29A0, 0x29A0, 154 + 0x29A0, 0x29A0, 0x29C0, 0x29C0, 155 + 0x29C0, 0x29E0, 0x29E0, 0x29E0, 156 + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ 157 + 0x2A00, 0x2A20, 0x2A20, 0x2A20, 158 + 0x2A20, 0x2A40, 0x2A40, 0x2A40, 159 + 0x2A40, 0x2A60, 0x2A60, 0x2A60, 160 + }; 161 + 162 + const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = { 163 + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ 164 + 0x05A9, 0x0669, 0x0709, 0x0789, 165 + 0x0829, 0x08A9, 0x0929, 0x0989, 166 + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, 167 + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ 168 + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, 169 + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, 170 + 0x0FA9, 0x0FE9, 0x1029, 0x1089, 171 + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ 172 + 0x11E9, 0x1229, 0x1289, 0x12C9, 173 + 0x1309, 0x1349, 0x1389, 0x13C9, 174 + 0x1409, 0x1449, 0x14A9, 0x14E9, 175 + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ 176 + 0x1629, 0x1669, 0x16A9, 0x16E8, 177 + 0x1728, 0x1768, 0x17A8, 0x17E8, 178 + 0x1828, 0x1868, 0x18A8, 0x18E8, 179 + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ 180 + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, 181 + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, 182 + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, 183 + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ 184 + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, 185 + 0x1F48, 0x1F88, 0x1FE8, 0x2028, 186 + 0x2068, 0x20A8, 0x2108, 0x2148, 187 + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ 188 + 0x22C8, 0x2308, 0x2348, 0x23A8, 189 + 0x23E8, 0x2448, 0x24A8, 0x24E8, 190 + 0x2548, 0x25A8, 0x2608, 0x2668, 191 + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ 192 + 0x2847, 0x28C7, 0x2947, 0x29A7, 193 + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, 194 + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, 195 + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ 196 + 0x3806, 0x38A6, 0x3946, 0x39E6, 197 + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, 198 + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, 199 + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ 200 + 0x3F45, 0x3FA5, 0x4005, 0x4045, 201 + 0x40A5, 0x40E5, 0x4145, 0x4185, 202 + 0x41E5, 0x4225, 0x4265, 0x42C5, 203 + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ 204 + 0x4424, 0x4464, 0x44C4, 0x4504, 205 + 0x4544, 0x4584, 0x45C4, 0x4604, 206 + 0x4644, 0x46A4, 0x46E4, 0x4724, 207 + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ 208 + 0x4864, 0x48A4, 0x48E4, 0x4924, 209 + 0x4964, 0x49A4, 0x49E4, 0x4A24, 210 + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, 211 + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ 212 + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, 213 + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, 214 + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, 215 + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ 216 + 0x5083, 0x50C3, 0x5103, 0x5143, 217 + 0x5183, 0x51E2, 0x5222, 0x5262, 218 + 0x52A2, 0x52E2, 0x5342, 0x5382, 219 + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ 220 + 0x5502, 0x5542, 0x55A2, 0x55E2, 221 + 0x5642, 0x5682, 0x56E2, 0x5722, 222 + 0x5782, 0x57E1, 0x5841, 0x58A1, 223 + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ 224 + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, 225 + 0x5C61, 0x5D01, 0x5D80, 0x5E20, 226 + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, 227 + }; 228 + 229 + const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = { 230 + 0x0001, 0x0001, 0x0001, 0xFFFE, 231 + 0xFFFE, 0x3FFF, 0x1000, 0x0393, 232 + }; 233 + 234 + const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = { 235 + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, 236 + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, 237 + }; 238 + 239 + const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = { 240 + 0x013C, 0x01F5, 0x031A, 0x0631, 241 + 0x0001, 0x0001, 0x0001, 0x0001, 242 + }; 243 + 244 + const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = { 245 + 0x5484, 0x3C40, 0x0000, 0x0000, 246 + 0x0000, 0x0000, 0x0000, 0x0000, 247 + }; 248 + 249 + const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = { 250 + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ 251 + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, 252 + 0x1A1D, 0x1719, 0x1616, 0x1414, 253 + 0x1414, 0x1400, 0x1414, 0x1614, 254 + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ 255 + 0x2A27, 0x2F2A, 0x332D, 0x3B35, 256 + 0x5140, 0x6C62, 0x0077, 257 + }; 258 + 259 + const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = { 260 + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ 261 + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, 262 + 0x969B, 0x9195, 0x8F8F, 0x8A8A, 263 + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, 264 + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ 265 + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, 266 + 0xCBC0, 0xD8D4, 0x00DD, 267 + }; 268 + 269 + const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = { 270 + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ 271 + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, 272 + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, 273 + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, 274 + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ 275 + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, 276 + 0xA4A4, 0xA4A4, 0x00A4, 277 + }; 278 + 279 + const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = { 280 + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ 281 + 0x0067, 0x0063, 0x005E, 0x0059, 282 + 0x0054, 0x0050, 0x004B, 0x0046, 283 + 0x0042, 0x003D, 0x003D, 0x003D, 284 + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ 285 + 0x003D, 0x003D, 0x003D, 0x003D, 286 + 0x003D, 0x003D, 0x0000, 0x003D, 287 + 0x003D, 0x003D, 0x003D, 0x003D, 288 + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ 289 + 0x003D, 0x003D, 0x003D, 0x003D, 290 + 0x0042, 0x0046, 0x004B, 0x0050, 291 + 0x0054, 0x0059, 0x005E, 0x0063, 292 + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ 293 + 0x007A, 294 + }; 295 + 296 + const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { 297 + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ 298 + 0x00D6, 0x00D4, 0x00D2, 0x00CF, 299 + 0x00CD, 0x00CA, 0x00C7, 0x00C4, 300 + 0x00C1, 0x00BE, 0x00BE, 0x00BE, 301 + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ 302 + 0x00BE, 0x00BE, 0x00BE, 0x00BE, 303 + 0x00BE, 0x00BE, 0x0000, 0x00BE, 304 + 0x00BE, 0x00BE, 0x00BE, 0x00BE, 305 + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ 306 + 0x00BE, 0x00BE, 0x00BE, 0x00BE, 307 + 0x00C1, 0x00C4, 0x00C7, 0x00CA, 308 + 0x00CD, 0x00CF, 0x00D2, 0x00D4, 309 + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ 310 + 0x00DE, 311 + }; 312 + 313 + /**** Helper functions to access the device Internal Lookup Tables ****/ 314 + 315 + void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) 316 + { 317 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { 318 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); 319 + mmiowb(); 320 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); 321 + } else { 322 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); 323 + mmiowb(); 324 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val); 325 + } 326 + } 327 + 328 + u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) 329 + { 330 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { 331 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); 332 + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); 333 + } else { 334 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); 335 + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); 336 + } 337 + }
+32
drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
··· 1 + #ifndef BCM43xx_ILT_H_ 2 + #define BCM43xx_ILT_H_ 3 + 4 + #define BCM43xx_ILT_ROTOR_SIZE 53 5 + extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE]; 6 + #define BCM43xx_ILT_RETARD_SIZE 53 7 + extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE]; 8 + #define BCM43xx_ILT_FINEFREQA_SIZE 256 9 + extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE]; 10 + #define BCM43xx_ILT_FINEFREQG_SIZE 256 11 + extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE]; 12 + #define BCM43xx_ILT_NOISEA2_SIZE 8 13 + extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE]; 14 + #define BCM43xx_ILT_NOISEA3_SIZE 8 15 + extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE]; 16 + #define BCM43xx_ILT_NOISEG1_SIZE 8 17 + extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE]; 18 + #define BCM43xx_ILT_NOISEG2_SIZE 8 19 + extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE]; 20 + #define BCM43xx_ILT_NOISESCALEG_SIZE 27 21 + extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE]; 22 + extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE]; 23 + extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE]; 24 + #define BCM43xx_ILT_SIGMASQR_SIZE 53 25 + extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE]; 26 + extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE]; 27 + 28 + 29 + void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val); 30 + u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset); 31 + 32 + #endif /* BCM43xx_ILT_H_ */
+293
drivers/net/wireless/bcm43xx/bcm43xx_leds.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + This program is free software; you can redistribute it and/or modify 12 + it under the terms of the GNU General Public License as published by 13 + the Free Software Foundation; either version 2 of the License, or 14 + (at your option) any later version. 15 + 16 + This program is distributed in the hope that it will be useful, 17 + but WITHOUT ANY WARRANTY; without even the implied warranty of 18 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + GNU General Public License for more details. 20 + 21 + You should have received a copy of the GNU General Public License 22 + along with this program; see the file COPYING. If not, write to 23 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 24 + Boston, MA 02110-1301, USA. 25 + 26 + */ 27 + 28 + #include "bcm43xx_leds.h" 29 + #include "bcm43xx.h" 30 + 31 + #include <asm/bitops.h> 32 + 33 + 34 + static void bcm43xx_led_changestate(struct bcm43xx_led *led) 35 + { 36 + struct bcm43xx_private *bcm = led->bcm; 37 + const int index = bcm43xx_led_index(led); 38 + const u16 mask = (1 << index); 39 + u16 ledctl; 40 + 41 + assert(index >= 0 && index < BCM43xx_NR_LEDS); 42 + assert(led->blink_interval); 43 + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); 44 + ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); 45 + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); 46 + } 47 + 48 + static void bcm43xx_led_blink(unsigned long d) 49 + { 50 + struct bcm43xx_led *led = (struct bcm43xx_led *)d; 51 + struct bcm43xx_private *bcm = led->bcm; 52 + unsigned long flags; 53 + 54 + bcm43xx_lock_mmio(bcm, flags); 55 + if (led->blink_interval) { 56 + bcm43xx_led_changestate(led); 57 + mod_timer(&led->blink_timer, jiffies + led->blink_interval); 58 + } 59 + bcm43xx_unlock_mmio(bcm, flags); 60 + } 61 + 62 + static void bcm43xx_led_blink_start(struct bcm43xx_led *led, 63 + unsigned long interval) 64 + { 65 + if (led->blink_interval) 66 + return; 67 + led->blink_interval = interval; 68 + bcm43xx_led_changestate(led); 69 + led->blink_timer.expires = jiffies + interval; 70 + add_timer(&led->blink_timer); 71 + } 72 + 73 + static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync) 74 + { 75 + struct bcm43xx_private *bcm = led->bcm; 76 + const int index = bcm43xx_led_index(led); 77 + u16 ledctl; 78 + 79 + if (!led->blink_interval) 80 + return; 81 + if (unlikely(sync)) 82 + del_timer_sync(&led->blink_timer); 83 + else 84 + del_timer(&led->blink_timer); 85 + led->blink_interval = 0; 86 + 87 + /* Make sure the LED is turned off. */ 88 + assert(index >= 0 && index < BCM43xx_NR_LEDS); 89 + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); 90 + if (led->activelow) 91 + ledctl |= (1 << index); 92 + else 93 + ledctl &= ~(1 << index); 94 + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); 95 + } 96 + 97 + static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm, 98 + struct bcm43xx_led *led, 99 + int led_index) 100 + { 101 + /* This function is called, if the behaviour (and activelow) 102 + * information for a LED is missing in the SPROM. 103 + * We hardcode the behaviour values for various devices here. 104 + * Note that the BCM43xx_LED_TEST_XXX behaviour values can 105 + * be used to figure out which led is mapped to which index. 106 + */ 107 + 108 + switch (led_index) { 109 + case 0: 110 + led->behaviour = BCM43xx_LED_ACTIVITY; 111 + if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) 112 + led->behaviour = BCM43xx_LED_RADIO_ALL; 113 + break; 114 + case 1: 115 + led->behaviour = BCM43xx_LED_RADIO_B; 116 + if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK) 117 + led->behaviour = BCM43xx_LED_ASSOC; 118 + break; 119 + case 2: 120 + led->behaviour = BCM43xx_LED_RADIO_A; 121 + break; 122 + case 3: 123 + led->behaviour = BCM43xx_LED_OFF; 124 + break; 125 + default: 126 + assert(0); 127 + } 128 + } 129 + 130 + int bcm43xx_leds_init(struct bcm43xx_private *bcm) 131 + { 132 + struct bcm43xx_led *led; 133 + u8 sprom[4]; 134 + int i; 135 + 136 + sprom[0] = bcm->sprom.wl0gpio0; 137 + sprom[1] = bcm->sprom.wl0gpio1; 138 + sprom[2] = bcm->sprom.wl0gpio2; 139 + sprom[3] = bcm->sprom.wl0gpio3; 140 + 141 + for (i = 0; i < BCM43xx_NR_LEDS; i++) { 142 + led = &(bcm->leds[i]); 143 + led->bcm = bcm; 144 + setup_timer(&led->blink_timer, 145 + bcm43xx_led_blink, 146 + (unsigned long)led); 147 + 148 + if (sprom[i] == 0xFF) { 149 + bcm43xx_led_init_hardcoded(bcm, led, i); 150 + } else { 151 + led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR; 152 + led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW); 153 + } 154 + } 155 + 156 + return 0; 157 + } 158 + 159 + void bcm43xx_leds_exit(struct bcm43xx_private *bcm) 160 + { 161 + struct bcm43xx_led *led; 162 + int i; 163 + 164 + for (i = 0; i < BCM43xx_NR_LEDS; i++) { 165 + led = &(bcm->leds[i]); 166 + bcm43xx_led_blink_stop(led, 1); 167 + } 168 + bcm43xx_leds_switch_all(bcm, 0); 169 + } 170 + 171 + void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) 172 + { 173 + struct bcm43xx_led *led; 174 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 175 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 176 + const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; 177 + int i, turn_on; 178 + unsigned long interval = 0; 179 + u16 ledctl; 180 + 181 + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); 182 + for (i = 0; i < BCM43xx_NR_LEDS; i++) { 183 + led = &(bcm->leds[i]); 184 + 185 + turn_on = 0; 186 + switch (led->behaviour) { 187 + case BCM43xx_LED_INACTIVE: 188 + continue; 189 + case BCM43xx_LED_OFF: 190 + break; 191 + case BCM43xx_LED_ON: 192 + turn_on = 1; 193 + break; 194 + case BCM43xx_LED_ACTIVITY: 195 + turn_on = activity; 196 + break; 197 + case BCM43xx_LED_RADIO_ALL: 198 + turn_on = radio->enabled; 199 + break; 200 + case BCM43xx_LED_RADIO_A: 201 + turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A); 202 + break; 203 + case BCM43xx_LED_RADIO_B: 204 + turn_on = (radio->enabled && 205 + (phy->type == BCM43xx_PHYTYPE_B || 206 + phy->type == BCM43xx_PHYTYPE_G)); 207 + break; 208 + case BCM43xx_LED_MODE_BG: 209 + if (phy->type == BCM43xx_PHYTYPE_G && 210 + 1/*FIXME: using G rates.*/) 211 + turn_on = 1; 212 + break; 213 + case BCM43xx_LED_TRANSFER: 214 + if (transferring) 215 + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); 216 + else 217 + bcm43xx_led_blink_stop(led, 0); 218 + continue; 219 + case BCM43xx_LED_APTRANSFER: 220 + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { 221 + if (transferring) { 222 + interval = BCM43xx_LEDBLINK_FAST; 223 + turn_on = 1; 224 + } 225 + } else { 226 + turn_on = 1; 227 + if (0/*TODO: not assoc*/) 228 + interval = BCM43xx_LEDBLINK_SLOW; 229 + else if (transferring) 230 + interval = BCM43xx_LEDBLINK_FAST; 231 + else 232 + turn_on = 0; 233 + } 234 + if (turn_on) 235 + bcm43xx_led_blink_start(led, interval); 236 + else 237 + bcm43xx_led_blink_stop(led, 0); 238 + continue; 239 + case BCM43xx_LED_WEIRD: 240 + //TODO 241 + break; 242 + case BCM43xx_LED_ASSOC: 243 + if (bcm->softmac->associated) 244 + turn_on = 1; 245 + break; 246 + #ifdef CONFIG_BCM43XX_DEBUG 247 + case BCM43xx_LED_TEST_BLINKSLOW: 248 + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW); 249 + continue; 250 + case BCM43xx_LED_TEST_BLINKMEDIUM: 251 + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); 252 + continue; 253 + case BCM43xx_LED_TEST_BLINKFAST: 254 + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST); 255 + continue; 256 + #endif /* CONFIG_BCM43XX_DEBUG */ 257 + default: 258 + assert(0); 259 + }; 260 + 261 + if (led->activelow) 262 + turn_on = !turn_on; 263 + if (turn_on) 264 + ledctl |= (1 << i); 265 + else 266 + ledctl &= ~(1 << i); 267 + } 268 + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); 269 + } 270 + 271 + void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) 272 + { 273 + struct bcm43xx_led *led; 274 + u16 ledctl; 275 + int i; 276 + int bit_on; 277 + 278 + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); 279 + for (i = 0; i < BCM43xx_NR_LEDS; i++) { 280 + led = &(bcm->leds[i]); 281 + if (led->behaviour == BCM43xx_LED_INACTIVE) 282 + continue; 283 + if (on) 284 + bit_on = led->activelow ? 0 : 1; 285 + else 286 + bit_on = led->activelow ? 1 : 0; 287 + if (bit_on) 288 + ledctl |= (1 << i); 289 + else 290 + ledctl &= ~(1 << i); 291 + } 292 + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); 293 + }
+56
drivers/net/wireless/bcm43xx/bcm43xx_leds.h
··· 1 + #ifndef BCM43xx_LEDS_H_ 2 + #define BCM43xx_LEDS_H_ 3 + 4 + #include <linux/types.h> 5 + #include <linux/timer.h> 6 + 7 + 8 + struct bcm43xx_led { 9 + u8 behaviour:7; 10 + u8 activelow:1; 11 + 12 + struct bcm43xx_private *bcm; 13 + struct timer_list blink_timer; 14 + unsigned long blink_interval; 15 + }; 16 + #define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds)) 17 + 18 + /* Delay between state changes when blinking in jiffies */ 19 + #define BCM43xx_LEDBLINK_SLOW (HZ / 1) 20 + #define BCM43xx_LEDBLINK_MEDIUM (HZ / 4) 21 + #define BCM43xx_LEDBLINK_FAST (HZ / 8) 22 + 23 + #define BCM43xx_LED_XFER_THRES (HZ / 100) 24 + 25 + #define BCM43xx_LED_BEHAVIOUR 0x7F 26 + #define BCM43xx_LED_ACTIVELOW 0x80 27 + enum { /* LED behaviour values */ 28 + BCM43xx_LED_OFF, 29 + BCM43xx_LED_ON, 30 + BCM43xx_LED_ACTIVITY, 31 + BCM43xx_LED_RADIO_ALL, 32 + BCM43xx_LED_RADIO_A, 33 + BCM43xx_LED_RADIO_B, 34 + BCM43xx_LED_MODE_BG, 35 + BCM43xx_LED_TRANSFER, 36 + BCM43xx_LED_APTRANSFER, 37 + BCM43xx_LED_WEIRD,//FIXME 38 + BCM43xx_LED_ASSOC, 39 + BCM43xx_LED_INACTIVE, 40 + 41 + /* Behaviour values for testing. 42 + * With these values it is easier to figure out 43 + * the real behaviour of leds, in case the SPROM 44 + * is missing information. 45 + */ 46 + BCM43xx_LED_TEST_BLINKSLOW, 47 + BCM43xx_LED_TEST_BLINKMEDIUM, 48 + BCM43xx_LED_TEST_BLINKFAST, 49 + }; 50 + 51 + int bcm43xx_leds_init(struct bcm43xx_private *bcm); 52 + void bcm43xx_leds_exit(struct bcm43xx_private *bcm); 53 + void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity); 54 + void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on); 55 + 56 + #endif /* BCM43xx_LEDS_H_ */
+3973
drivers/net/wireless/bcm43xx/bcm43xx_main.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #include <linux/delay.h> 32 + #include <linux/init.h> 33 + #include <linux/moduleparam.h> 34 + #include <linux/if_arp.h> 35 + #include <linux/etherdevice.h> 36 + #include <linux/version.h> 37 + #include <linux/firmware.h> 38 + #include <linux/wireless.h> 39 + #include <linux/workqueue.h> 40 + #include <linux/skbuff.h> 41 + #include <linux/dma-mapping.h> 42 + #include <net/iw_handler.h> 43 + 44 + #include "bcm43xx.h" 45 + #include "bcm43xx_main.h" 46 + #include "bcm43xx_debugfs.h" 47 + #include "bcm43xx_radio.h" 48 + #include "bcm43xx_phy.h" 49 + #include "bcm43xx_dma.h" 50 + #include "bcm43xx_pio.h" 51 + #include "bcm43xx_power.h" 52 + #include "bcm43xx_wx.h" 53 + #include "bcm43xx_ethtool.h" 54 + #include "bcm43xx_xmit.h" 55 + 56 + 57 + MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); 58 + MODULE_AUTHOR("Martin Langer"); 59 + MODULE_AUTHOR("Stefano Brivio"); 60 + MODULE_AUTHOR("Michael Buesch"); 61 + MODULE_LICENSE("GPL"); 62 + 63 + #ifdef CONFIG_BCM947XX 64 + extern char *nvram_get(char *name); 65 + #endif 66 + 67 + #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) 68 + static int modparam_pio; 69 + module_param_named(pio, modparam_pio, int, 0444); 70 + MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); 71 + #elif defined(CONFIG_BCM43XX_DMA) 72 + # define modparam_pio 0 73 + #elif defined(CONFIG_BCM43XX_PIO) 74 + # define modparam_pio 1 75 + #endif 76 + 77 + static int modparam_bad_frames_preempt; 78 + module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); 79 + MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption"); 80 + 81 + static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT; 82 + module_param_named(short_retry, modparam_short_retry, int, 0444); 83 + MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); 84 + 85 + static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT; 86 + module_param_named(long_retry, modparam_long_retry, int, 0444); 87 + MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); 88 + 89 + static int modparam_locale = -1; 90 + module_param_named(locale, modparam_locale, int, 0444); 91 + MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)"); 92 + 93 + static int modparam_noleds; 94 + module_param_named(noleds, modparam_noleds, int, 0444); 95 + MODULE_PARM_DESC(noleds, "Turn off all LED activity"); 96 + 97 + #ifdef CONFIG_BCM43XX_DEBUG 98 + static char modparam_fwpostfix[64]; 99 + module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); 100 + MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); 101 + #else 102 + # define modparam_fwpostfix "" 103 + #endif /* CONFIG_BCM43XX_DEBUG*/ 104 + 105 + 106 + /* If you want to debug with just a single device, enable this, 107 + * where the string is the pci device ID (as given by the kernel's 108 + * pci_name function) of the device to be used. 109 + */ 110 + //#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0" 111 + 112 + /* If you want to enable printing of each MMIO access, enable this. */ 113 + //#define DEBUG_ENABLE_MMIO_PRINT 114 + 115 + /* If you want to enable printing of MMIO access within 116 + * ucode/pcm upload, initvals write, enable this. 117 + */ 118 + //#define DEBUG_ENABLE_UCODE_MMIO_PRINT 119 + 120 + /* If you want to enable printing of PCI Config Space access, enable this */ 121 + //#define DEBUG_ENABLE_PCILOG 122 + 123 + 124 + /* Detailed list maintained at: 125 + * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices 126 + */ 127 + static struct pci_device_id bcm43xx_pci_tbl[] = { 128 + /* Broadcom 4303 802.11b */ 129 + { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 130 + /* Broadcom 4307 802.11b */ 131 + { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 132 + /* Broadcom 4318 802.11b/g */ 133 + { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 134 + /* Broadcom 4306 802.11b/g */ 135 + { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 136 + /* Broadcom 4306 802.11a */ 137 + // { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 138 + /* Broadcom 4309 802.11a/b/g */ 139 + { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 140 + /* Broadcom 43XG 802.11b/g */ 141 + { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 142 + #ifdef CONFIG_BCM947XX 143 + /* SB bus on BCM947xx */ 144 + { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 145 + #endif 146 + { 0 }, 147 + }; 148 + MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl); 149 + 150 + static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val) 151 + { 152 + u32 status; 153 + 154 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 155 + if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP)) 156 + val = swab32(val); 157 + 158 + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); 159 + mmiowb(); 160 + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val); 161 + } 162 + 163 + static inline 164 + void bcm43xx_shm_control_word(struct bcm43xx_private *bcm, 165 + u16 routing, u16 offset) 166 + { 167 + u32 control; 168 + 169 + /* "offset" is the WORD offset. */ 170 + 171 + control = routing; 172 + control <<= 16; 173 + control |= offset; 174 + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control); 175 + } 176 + 177 + u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, 178 + u16 routing, u16 offset) 179 + { 180 + u32 ret; 181 + 182 + if (routing == BCM43xx_SHM_SHARED) { 183 + if (offset & 0x0003) { 184 + /* Unaligned access */ 185 + bcm43xx_shm_control_word(bcm, routing, offset >> 2); 186 + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); 187 + ret <<= 16; 188 + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); 189 + ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); 190 + 191 + return ret; 192 + } 193 + offset >>= 2; 194 + } 195 + bcm43xx_shm_control_word(bcm, routing, offset); 196 + ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA); 197 + 198 + return ret; 199 + } 200 + 201 + u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, 202 + u16 routing, u16 offset) 203 + { 204 + u16 ret; 205 + 206 + if (routing == BCM43xx_SHM_SHARED) { 207 + if (offset & 0x0003) { 208 + /* Unaligned access */ 209 + bcm43xx_shm_control_word(bcm, routing, offset >> 2); 210 + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); 211 + 212 + return ret; 213 + } 214 + offset >>= 2; 215 + } 216 + bcm43xx_shm_control_word(bcm, routing, offset); 217 + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); 218 + 219 + return ret; 220 + } 221 + 222 + void bcm43xx_shm_write32(struct bcm43xx_private *bcm, 223 + u16 routing, u16 offset, 224 + u32 value) 225 + { 226 + if (routing == BCM43xx_SHM_SHARED) { 227 + if (offset & 0x0003) { 228 + /* Unaligned access */ 229 + bcm43xx_shm_control_word(bcm, routing, offset >> 2); 230 + mmiowb(); 231 + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, 232 + (value >> 16) & 0xffff); 233 + mmiowb(); 234 + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); 235 + mmiowb(); 236 + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, 237 + value & 0xffff); 238 + return; 239 + } 240 + offset >>= 2; 241 + } 242 + bcm43xx_shm_control_word(bcm, routing, offset); 243 + mmiowb(); 244 + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value); 245 + } 246 + 247 + void bcm43xx_shm_write16(struct bcm43xx_private *bcm, 248 + u16 routing, u16 offset, 249 + u16 value) 250 + { 251 + if (routing == BCM43xx_SHM_SHARED) { 252 + if (offset & 0x0003) { 253 + /* Unaligned access */ 254 + bcm43xx_shm_control_word(bcm, routing, offset >> 2); 255 + mmiowb(); 256 + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, 257 + value); 258 + return; 259 + } 260 + offset >>= 2; 261 + } 262 + bcm43xx_shm_control_word(bcm, routing, offset); 263 + mmiowb(); 264 + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value); 265 + } 266 + 267 + void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf) 268 + { 269 + /* We need to be careful. As we read the TSF from multiple 270 + * registers, we should take care of register overflows. 271 + * In theory, the whole tsf read process should be atomic. 272 + * We try to be atomic here, by restaring the read process, 273 + * if any of the high registers changed (overflew). 274 + */ 275 + if (bcm->current_core->rev >= 3) { 276 + u32 low, high, high2; 277 + 278 + do { 279 + high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); 280 + low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW); 281 + high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); 282 + } while (unlikely(high != high2)); 283 + 284 + *tsf = high; 285 + *tsf <<= 32; 286 + *tsf |= low; 287 + } else { 288 + u64 tmp; 289 + u16 v0, v1, v2, v3; 290 + u16 test1, test2, test3; 291 + 292 + do { 293 + v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); 294 + v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); 295 + v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); 296 + v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0); 297 + 298 + test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); 299 + test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); 300 + test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); 301 + } while (v3 != test3 || v2 != test2 || v1 != test1); 302 + 303 + *tsf = v3; 304 + *tsf <<= 48; 305 + tmp = v2; 306 + tmp <<= 32; 307 + *tsf |= tmp; 308 + tmp = v1; 309 + tmp <<= 16; 310 + *tsf |= tmp; 311 + *tsf |= v0; 312 + } 313 + } 314 + 315 + void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) 316 + { 317 + u32 status; 318 + 319 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 320 + status |= BCM43xx_SBF_TIME_UPDATE; 321 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); 322 + mmiowb(); 323 + 324 + /* Be careful with the in-progress timer. 325 + * First zero out the low register, so we have a full 326 + * register-overflow duration to complete the operation. 327 + */ 328 + if (bcm->current_core->rev >= 3) { 329 + u32 lo = (tsf & 0x00000000FFFFFFFFULL); 330 + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; 331 + 332 + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); 333 + mmiowb(); 334 + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); 335 + mmiowb(); 336 + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); 337 + } else { 338 + u16 v0 = (tsf & 0x000000000000FFFFULL); 339 + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; 340 + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; 341 + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; 342 + 343 + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); 344 + mmiowb(); 345 + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); 346 + mmiowb(); 347 + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); 348 + mmiowb(); 349 + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); 350 + mmiowb(); 351 + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); 352 + } 353 + 354 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 355 + status &= ~BCM43xx_SBF_TIME_UPDATE; 356 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); 357 + } 358 + 359 + static 360 + void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, 361 + u16 offset, 362 + const u8 *mac) 363 + { 364 + u16 data; 365 + 366 + offset |= 0x0020; 367 + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset); 368 + 369 + data = mac[0]; 370 + data |= mac[1] << 8; 371 + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); 372 + data = mac[2]; 373 + data |= mac[3] << 8; 374 + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); 375 + data = mac[4]; 376 + data |= mac[5] << 8; 377 + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); 378 + } 379 + 380 + static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, 381 + u16 offset) 382 + { 383 + const u8 zero_addr[ETH_ALEN] = { 0 }; 384 + 385 + bcm43xx_macfilter_set(bcm, offset, zero_addr); 386 + } 387 + 388 + static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) 389 + { 390 + const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); 391 + const u8 *bssid = (const u8 *)(bcm->ieee->bssid); 392 + u8 mac_bssid[ETH_ALEN * 2]; 393 + int i; 394 + 395 + memcpy(mac_bssid, mac, ETH_ALEN); 396 + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); 397 + 398 + /* Write our MAC address and BSSID to template ram */ 399 + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) 400 + bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i))); 401 + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) 402 + bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i))); 403 + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) 404 + bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); 405 + } 406 + 407 + //FIXME: Well, we should probably call them from somewhere. 408 + #if 0 409 + static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) 410 + { 411 + /* slot_time is in usec. */ 412 + if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G) 413 + return; 414 + bcm43xx_write16(bcm, 0x684, 510 + slot_time); 415 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); 416 + } 417 + 418 + static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) 419 + { 420 + bcm43xx_set_slot_time(bcm, 9); 421 + } 422 + 423 + static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) 424 + { 425 + bcm43xx_set_slot_time(bcm, 20); 426 + } 427 + #endif 428 + 429 + /* FIXME: To get the MAC-filter working, we need to implement the 430 + * following functions (and rename them :) 431 + */ 432 + #if 0 433 + static void bcm43xx_disassociate(struct bcm43xx_private *bcm) 434 + { 435 + bcm43xx_mac_suspend(bcm); 436 + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); 437 + 438 + bcm43xx_ram_write(bcm, 0x0026, 0x0000); 439 + bcm43xx_ram_write(bcm, 0x0028, 0x0000); 440 + bcm43xx_ram_write(bcm, 0x007E, 0x0000); 441 + bcm43xx_ram_write(bcm, 0x0080, 0x0000); 442 + bcm43xx_ram_write(bcm, 0x047E, 0x0000); 443 + bcm43xx_ram_write(bcm, 0x0480, 0x0000); 444 + 445 + if (bcm->current_core->rev < 3) { 446 + bcm43xx_write16(bcm, 0x0610, 0x8000); 447 + bcm43xx_write16(bcm, 0x060E, 0x0000); 448 + } else 449 + bcm43xx_write32(bcm, 0x0188, 0x80000000); 450 + 451 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); 452 + 453 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G && 454 + ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) 455 + bcm43xx_short_slot_timing_enable(bcm); 456 + 457 + bcm43xx_mac_enable(bcm); 458 + } 459 + 460 + static void bcm43xx_associate(struct bcm43xx_private *bcm, 461 + const u8 *mac) 462 + { 463 + memcpy(bcm->ieee->bssid, mac, ETH_ALEN); 464 + 465 + bcm43xx_mac_suspend(bcm); 466 + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac); 467 + bcm43xx_write_mac_bssid_templates(bcm); 468 + bcm43xx_mac_enable(bcm); 469 + } 470 + #endif 471 + 472 + /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. 473 + * Returns the _previously_ enabled IRQ mask. 474 + */ 475 + static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask) 476 + { 477 + u32 old_mask; 478 + 479 + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); 480 + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask); 481 + 482 + return old_mask; 483 + } 484 + 485 + /* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. 486 + * Returns the _previously_ enabled IRQ mask. 487 + */ 488 + static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask) 489 + { 490 + u32 old_mask; 491 + 492 + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); 493 + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask); 494 + 495 + return old_mask; 496 + } 497 + 498 + /* Make sure we don't receive more data from the device. */ 499 + static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) 500 + { 501 + u32 old; 502 + unsigned long flags; 503 + 504 + bcm43xx_lock_mmio(bcm, flags); 505 + if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { 506 + bcm43xx_unlock_mmio(bcm, flags); 507 + return -EBUSY; 508 + } 509 + old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 510 + tasklet_disable(&bcm->isr_tasklet); 511 + bcm43xx_unlock_mmio(bcm, flags); 512 + if (oldstate) 513 + *oldstate = old; 514 + 515 + return 0; 516 + } 517 + 518 + static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) 519 + { 520 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 521 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 522 + u32 radio_id; 523 + u16 manufact; 524 + u16 version; 525 + u8 revision; 526 + s8 i; 527 + 528 + if (bcm->chip_id == 0x4317) { 529 + if (bcm->chip_rev == 0x00) 530 + radio_id = 0x3205017F; 531 + else if (bcm->chip_rev == 0x01) 532 + radio_id = 0x4205017F; 533 + else 534 + radio_id = 0x5205017F; 535 + } else { 536 + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); 537 + radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH); 538 + radio_id <<= 16; 539 + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); 540 + radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); 541 + } 542 + 543 + manufact = (radio_id & 0x00000FFF); 544 + version = (radio_id & 0x0FFFF000) >> 12; 545 + revision = (radio_id & 0xF0000000) >> 28; 546 + 547 + dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", 548 + radio_id, manufact, version, revision); 549 + 550 + switch (phy->type) { 551 + case BCM43xx_PHYTYPE_A: 552 + if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f)) 553 + goto err_unsupported_radio; 554 + break; 555 + case BCM43xx_PHYTYPE_B: 556 + if ((version & 0xFFF0) != 0x2050) 557 + goto err_unsupported_radio; 558 + break; 559 + case BCM43xx_PHYTYPE_G: 560 + if (version != 0x2050) 561 + goto err_unsupported_radio; 562 + break; 563 + } 564 + 565 + radio->manufact = manufact; 566 + radio->version = version; 567 + radio->revision = revision; 568 + 569 + /* Set default attenuation values. */ 570 + radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); 571 + radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); 572 + radio->txctl1 = bcm43xx_default_txctl1(bcm); 573 + radio->txctl2 = 0xFFFF; 574 + if (phy->type == BCM43xx_PHYTYPE_A) 575 + radio->txpower_desired = bcm->sprom.maxpower_aphy; 576 + else 577 + radio->txpower_desired = bcm->sprom.maxpower_bgphy; 578 + 579 + /* Initialize the in-memory nrssi Lookup Table. */ 580 + for (i = 0; i < 64; i++) 581 + radio->nrssi_lt[i] = i; 582 + 583 + return 0; 584 + 585 + err_unsupported_radio: 586 + printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n"); 587 + return -ENODEV; 588 + } 589 + 590 + static const char * bcm43xx_locale_iso(u8 locale) 591 + { 592 + /* ISO 3166-1 country codes. 593 + * Note that there aren't ISO 3166-1 codes for 594 + * all or locales. (Not all locales are countries) 595 + */ 596 + switch (locale) { 597 + case BCM43xx_LOCALE_WORLD: 598 + case BCM43xx_LOCALE_ALL: 599 + return "XX"; 600 + case BCM43xx_LOCALE_THAILAND: 601 + return "TH"; 602 + case BCM43xx_LOCALE_ISRAEL: 603 + return "IL"; 604 + case BCM43xx_LOCALE_JORDAN: 605 + return "JO"; 606 + case BCM43xx_LOCALE_CHINA: 607 + return "CN"; 608 + case BCM43xx_LOCALE_JAPAN: 609 + case BCM43xx_LOCALE_JAPAN_HIGH: 610 + return "JP"; 611 + case BCM43xx_LOCALE_USA_CANADA_ANZ: 612 + case BCM43xx_LOCALE_USA_LOW: 613 + return "US"; 614 + case BCM43xx_LOCALE_EUROPE: 615 + return "EU"; 616 + case BCM43xx_LOCALE_NONE: 617 + return " "; 618 + } 619 + assert(0); 620 + return " "; 621 + } 622 + 623 + static const char * bcm43xx_locale_string(u8 locale) 624 + { 625 + switch (locale) { 626 + case BCM43xx_LOCALE_WORLD: 627 + return "World"; 628 + case BCM43xx_LOCALE_THAILAND: 629 + return "Thailand"; 630 + case BCM43xx_LOCALE_ISRAEL: 631 + return "Israel"; 632 + case BCM43xx_LOCALE_JORDAN: 633 + return "Jordan"; 634 + case BCM43xx_LOCALE_CHINA: 635 + return "China"; 636 + case BCM43xx_LOCALE_JAPAN: 637 + return "Japan"; 638 + case BCM43xx_LOCALE_USA_CANADA_ANZ: 639 + return "USA/Canada/ANZ"; 640 + case BCM43xx_LOCALE_EUROPE: 641 + return "Europe"; 642 + case BCM43xx_LOCALE_USA_LOW: 643 + return "USAlow"; 644 + case BCM43xx_LOCALE_JAPAN_HIGH: 645 + return "JapanHigh"; 646 + case BCM43xx_LOCALE_ALL: 647 + return "All"; 648 + case BCM43xx_LOCALE_NONE: 649 + return "None"; 650 + } 651 + assert(0); 652 + return ""; 653 + } 654 + 655 + static inline u8 bcm43xx_crc8(u8 crc, u8 data) 656 + { 657 + static const u8 t[] = { 658 + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, 659 + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, 660 + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, 661 + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, 662 + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, 663 + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, 664 + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, 665 + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, 666 + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, 667 + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, 668 + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, 669 + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, 670 + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, 671 + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, 672 + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, 673 + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, 674 + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, 675 + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, 676 + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, 677 + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, 678 + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, 679 + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, 680 + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, 681 + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, 682 + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, 683 + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, 684 + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, 685 + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, 686 + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, 687 + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, 688 + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, 689 + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, 690 + }; 691 + return t[crc ^ data]; 692 + } 693 + 694 + static u8 bcm43xx_sprom_crc(const u16 *sprom) 695 + { 696 + int word; 697 + u8 crc = 0xFF; 698 + 699 + for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) { 700 + crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF); 701 + crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8); 702 + } 703 + crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF); 704 + crc ^= 0xFF; 705 + 706 + return crc; 707 + } 708 + 709 + int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom) 710 + { 711 + int i; 712 + u8 crc, expected_crc; 713 + 714 + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) 715 + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); 716 + /* CRC-8 check. */ 717 + crc = bcm43xx_sprom_crc(sprom); 718 + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; 719 + if (crc != expected_crc) { 720 + printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " 721 + "(0x%02X, expected: 0x%02X)\n", 722 + crc, expected_crc); 723 + return -EINVAL; 724 + } 725 + 726 + return 0; 727 + } 728 + 729 + int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) 730 + { 731 + int i, err; 732 + u8 crc, expected_crc; 733 + u32 spromctl; 734 + 735 + /* CRC-8 validation of the input data. */ 736 + crc = bcm43xx_sprom_crc(sprom); 737 + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; 738 + if (crc != expected_crc) { 739 + printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); 740 + return -EINVAL; 741 + } 742 + 743 + printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); 744 + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); 745 + if (err) 746 + goto err_ctlreg; 747 + spromctl |= 0x10; /* SPROM WRITE enable. */ 748 + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); 749 + if (err) 750 + goto err_ctlreg; 751 + /* We must burn lots of CPU cycles here, but that does not 752 + * really matter as one does not write the SPROM every other minute... 753 + */ 754 + printk(KERN_INFO PFX "[ 0%%"); 755 + mdelay(500); 756 + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { 757 + if (i == 16) 758 + printk("25%%"); 759 + else if (i == 32) 760 + printk("50%%"); 761 + else if (i == 48) 762 + printk("75%%"); 763 + else if (i % 2) 764 + printk("."); 765 + bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); 766 + mmiowb(); 767 + mdelay(20); 768 + } 769 + spromctl &= ~0x10; /* SPROM WRITE enable. */ 770 + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); 771 + if (err) 772 + goto err_ctlreg; 773 + mdelay(500); 774 + printk("100%% ]\n"); 775 + printk(KERN_INFO PFX "SPROM written.\n"); 776 + bcm43xx_controller_restart(bcm, "SPROM update"); 777 + 778 + return 0; 779 + err_ctlreg: 780 + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); 781 + return -ENODEV; 782 + } 783 + 784 + static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) 785 + { 786 + u16 value; 787 + u16 *sprom; 788 + #ifdef CONFIG_BCM947XX 789 + char *c; 790 + #endif 791 + 792 + sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16), 793 + GFP_KERNEL); 794 + if (!sprom) { 795 + printk(KERN_ERR PFX "sprom_extract OOM\n"); 796 + return -ENOMEM; 797 + } 798 + #ifdef CONFIG_BCM947XX 799 + sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2")); 800 + sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags")); 801 + 802 + if ((c = nvram_get("il0macaddr")) != NULL) 803 + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR])); 804 + 805 + if ((c = nvram_get("et1macaddr")) != NULL) 806 + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR])); 807 + 808 + sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0")); 809 + sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1")); 810 + sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2")); 811 + 812 + sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0")); 813 + sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1")); 814 + sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2")); 815 + 816 + sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev")); 817 + #else 818 + bcm43xx_sprom_read(bcm, sprom); 819 + #endif 820 + 821 + /* boardflags2 */ 822 + value = sprom[BCM43xx_SPROM_BOARDFLAGS2]; 823 + bcm->sprom.boardflags2 = value; 824 + 825 + /* il0macaddr */ 826 + value = sprom[BCM43xx_SPROM_IL0MACADDR + 0]; 827 + *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value); 828 + value = sprom[BCM43xx_SPROM_IL0MACADDR + 1]; 829 + *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value); 830 + value = sprom[BCM43xx_SPROM_IL0MACADDR + 2]; 831 + *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value); 832 + 833 + /* et0macaddr */ 834 + value = sprom[BCM43xx_SPROM_ET0MACADDR + 0]; 835 + *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value); 836 + value = sprom[BCM43xx_SPROM_ET0MACADDR + 1]; 837 + *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value); 838 + value = sprom[BCM43xx_SPROM_ET0MACADDR + 2]; 839 + *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value); 840 + 841 + /* et1macaddr */ 842 + value = sprom[BCM43xx_SPROM_ET1MACADDR + 0]; 843 + *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value); 844 + value = sprom[BCM43xx_SPROM_ET1MACADDR + 1]; 845 + *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value); 846 + value = sprom[BCM43xx_SPROM_ET1MACADDR + 2]; 847 + *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value); 848 + 849 + /* ethernet phy settings */ 850 + value = sprom[BCM43xx_SPROM_ETHPHY]; 851 + bcm->sprom.et0phyaddr = (value & 0x001F); 852 + bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5; 853 + bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14; 854 + bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15; 855 + 856 + /* boardrev, antennas, locale */ 857 + value = sprom[BCM43xx_SPROM_BOARDREV]; 858 + bcm->sprom.boardrev = (value & 0x00FF); 859 + bcm->sprom.locale = (value & 0x0F00) >> 8; 860 + bcm->sprom.antennas_aphy = (value & 0x3000) >> 12; 861 + bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14; 862 + if (modparam_locale != -1) { 863 + if (modparam_locale >= 0 && modparam_locale <= 11) { 864 + bcm->sprom.locale = modparam_locale; 865 + printk(KERN_WARNING PFX "Operating with modified " 866 + "LocaleCode %u (%s)\n", 867 + bcm->sprom.locale, 868 + bcm43xx_locale_string(bcm->sprom.locale)); 869 + } else { 870 + printk(KERN_WARNING PFX "Module parameter \"locale\" " 871 + "invalid value. (0 - 11)\n"); 872 + } 873 + } 874 + 875 + /* pa0b* */ 876 + value = sprom[BCM43xx_SPROM_PA0B0]; 877 + bcm->sprom.pa0b0 = value; 878 + value = sprom[BCM43xx_SPROM_PA0B1]; 879 + bcm->sprom.pa0b1 = value; 880 + value = sprom[BCM43xx_SPROM_PA0B2]; 881 + bcm->sprom.pa0b2 = value; 882 + 883 + /* wl0gpio* */ 884 + value = sprom[BCM43xx_SPROM_WL0GPIO0]; 885 + if (value == 0x0000) 886 + value = 0xFFFF; 887 + bcm->sprom.wl0gpio0 = value & 0x00FF; 888 + bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8; 889 + value = sprom[BCM43xx_SPROM_WL0GPIO2]; 890 + if (value == 0x0000) 891 + value = 0xFFFF; 892 + bcm->sprom.wl0gpio2 = value & 0x00FF; 893 + bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8; 894 + 895 + /* maxpower */ 896 + value = sprom[BCM43xx_SPROM_MAXPWR]; 897 + bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8; 898 + bcm->sprom.maxpower_bgphy = value & 0x00FF; 899 + 900 + /* pa1b* */ 901 + value = sprom[BCM43xx_SPROM_PA1B0]; 902 + bcm->sprom.pa1b0 = value; 903 + value = sprom[BCM43xx_SPROM_PA1B1]; 904 + bcm->sprom.pa1b1 = value; 905 + value = sprom[BCM43xx_SPROM_PA1B2]; 906 + bcm->sprom.pa1b2 = value; 907 + 908 + /* idle tssi target */ 909 + value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT]; 910 + bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF; 911 + bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8; 912 + 913 + /* boardflags */ 914 + value = sprom[BCM43xx_SPROM_BOARDFLAGS]; 915 + if (value == 0xFFFF) 916 + value = 0x0000; 917 + bcm->sprom.boardflags = value; 918 + /* boardflags workarounds */ 919 + if (bcm->board_vendor == PCI_VENDOR_ID_DELL && 920 + bcm->chip_id == 0x4301 && 921 + bcm->board_revision == 0x74) 922 + bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST; 923 + if (bcm->board_vendor == PCI_VENDOR_ID_APPLE && 924 + bcm->board_type == 0x4E && 925 + bcm->board_revision > 0x40) 926 + bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL; 927 + 928 + /* antenna gain */ 929 + value = sprom[BCM43xx_SPROM_ANTENNA_GAIN]; 930 + if (value == 0x0000 || value == 0xFFFF) 931 + value = 0x0202; 932 + /* convert values to Q5.2 */ 933 + bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4; 934 + bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4; 935 + 936 + kfree(sprom); 937 + 938 + return 0; 939 + } 940 + 941 + static void bcm43xx_geo_init(struct bcm43xx_private *bcm) 942 + { 943 + struct ieee80211_geo geo; 944 + struct ieee80211_channel *chan; 945 + int have_a = 0, have_bg = 0; 946 + int i; 947 + u8 channel; 948 + struct bcm43xx_phyinfo *phy; 949 + const char *iso_country; 950 + 951 + memset(&geo, 0, sizeof(geo)); 952 + for (i = 0; i < bcm->nr_80211_available; i++) { 953 + phy = &(bcm->core_80211_ext[i].phy); 954 + switch (phy->type) { 955 + case BCM43xx_PHYTYPE_B: 956 + case BCM43xx_PHYTYPE_G: 957 + have_bg = 1; 958 + break; 959 + case BCM43xx_PHYTYPE_A: 960 + have_a = 1; 961 + break; 962 + default: 963 + assert(0); 964 + } 965 + } 966 + iso_country = bcm43xx_locale_iso(bcm->sprom.locale); 967 + 968 + if (have_a) { 969 + for (i = 0, channel = 0; channel < 201; channel++) { 970 + chan = &geo.a[i++]; 971 + chan->freq = bcm43xx_channel_to_freq_a(channel); 972 + chan->channel = channel; 973 + } 974 + geo.a_channels = i; 975 + } 976 + if (have_bg) { 977 + for (i = 0, channel = 1; channel < 15; channel++) { 978 + chan = &geo.bg[i++]; 979 + chan->freq = bcm43xx_channel_to_freq_bg(channel); 980 + chan->channel = channel; 981 + } 982 + geo.bg_channels = i; 983 + } 984 + memcpy(geo.name, iso_country, 2); 985 + if (0 /*TODO: Outdoor use only */) 986 + geo.name[2] = 'O'; 987 + else if (0 /*TODO: Indoor use only */) 988 + geo.name[2] = 'I'; 989 + else 990 + geo.name[2] = ' '; 991 + geo.name[3] = '\0'; 992 + 993 + ieee80211_set_geo(bcm->ieee, &geo); 994 + } 995 + 996 + /* DummyTransmission function, as documented on 997 + * http://bcm-specs.sipsolutions.net/DummyTransmission 998 + */ 999 + void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) 1000 + { 1001 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1002 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1003 + unsigned int i, max_loop; 1004 + u16 value = 0; 1005 + u32 buffer[5] = { 1006 + 0x00000000, 1007 + 0x0000D400, 1008 + 0x00000000, 1009 + 0x00000001, 1010 + 0x00000000, 1011 + }; 1012 + 1013 + switch (phy->type) { 1014 + case BCM43xx_PHYTYPE_A: 1015 + max_loop = 0x1E; 1016 + buffer[0] = 0xCC010200; 1017 + break; 1018 + case BCM43xx_PHYTYPE_B: 1019 + case BCM43xx_PHYTYPE_G: 1020 + max_loop = 0xFA; 1021 + buffer[0] = 0x6E840B00; 1022 + break; 1023 + default: 1024 + assert(0); 1025 + return; 1026 + } 1027 + 1028 + for (i = 0; i < 5; i++) 1029 + bcm43xx_ram_write(bcm, i * 4, buffer[i]); 1030 + 1031 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ 1032 + 1033 + bcm43xx_write16(bcm, 0x0568, 0x0000); 1034 + bcm43xx_write16(bcm, 0x07C0, 0x0000); 1035 + bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); 1036 + bcm43xx_write16(bcm, 0x0508, 0x0000); 1037 + bcm43xx_write16(bcm, 0x050A, 0x0000); 1038 + bcm43xx_write16(bcm, 0x054C, 0x0000); 1039 + bcm43xx_write16(bcm, 0x056A, 0x0014); 1040 + bcm43xx_write16(bcm, 0x0568, 0x0826); 1041 + bcm43xx_write16(bcm, 0x0500, 0x0000); 1042 + bcm43xx_write16(bcm, 0x0502, 0x0030); 1043 + 1044 + if (radio->version == 0x2050 && radio->revision <= 0x5) 1045 + bcm43xx_radio_write16(bcm, 0x0051, 0x0017); 1046 + for (i = 0x00; i < max_loop; i++) { 1047 + value = bcm43xx_read16(bcm, 0x050E); 1048 + if (value & 0x0080) 1049 + break; 1050 + udelay(10); 1051 + } 1052 + for (i = 0x00; i < 0x0A; i++) { 1053 + value = bcm43xx_read16(bcm, 0x050E); 1054 + if (value & 0x0400) 1055 + break; 1056 + udelay(10); 1057 + } 1058 + for (i = 0x00; i < 0x0A; i++) { 1059 + value = bcm43xx_read16(bcm, 0x0690); 1060 + if (!(value & 0x0100)) 1061 + break; 1062 + udelay(10); 1063 + } 1064 + if (radio->version == 0x2050 && radio->revision <= 0x5) 1065 + bcm43xx_radio_write16(bcm, 0x0051, 0x0037); 1066 + } 1067 + 1068 + static void key_write(struct bcm43xx_private *bcm, 1069 + u8 index, u8 algorithm, const u16 *key) 1070 + { 1071 + unsigned int i, basic_wep = 0; 1072 + u32 offset; 1073 + u16 value; 1074 + 1075 + /* Write associated key information */ 1076 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2), 1077 + ((index << 4) | (algorithm & 0x0F))); 1078 + 1079 + /* The first 4 WEP keys need extra love */ 1080 + if (((algorithm == BCM43xx_SEC_ALGO_WEP) || 1081 + (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4)) 1082 + basic_wep = 1; 1083 + 1084 + /* Write key payload, 8 little endian words */ 1085 + offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE); 1086 + for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) { 1087 + value = cpu_to_le16(key[i]); 1088 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 1089 + offset + (i * 2), value); 1090 + 1091 + if (!basic_wep) 1092 + continue; 1093 + 1094 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 1095 + offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE, 1096 + value); 1097 + } 1098 + } 1099 + 1100 + static void keymac_write(struct bcm43xx_private *bcm, 1101 + u8 index, const u32 *addr) 1102 + { 1103 + /* for keys 0-3 there is no associated mac address */ 1104 + if (index < 4) 1105 + return; 1106 + 1107 + index -= 4; 1108 + if (bcm->current_core->rev >= 5) { 1109 + bcm43xx_shm_write32(bcm, 1110 + BCM43xx_SHM_HWMAC, 1111 + index * 2, 1112 + cpu_to_be32(*addr)); 1113 + bcm43xx_shm_write16(bcm, 1114 + BCM43xx_SHM_HWMAC, 1115 + (index * 2) + 1, 1116 + cpu_to_be16(*((u16 *)(addr + 1)))); 1117 + } else { 1118 + if (index < 8) { 1119 + TODO(); /* Put them in the macaddress filter */ 1120 + } else { 1121 + TODO(); 1122 + /* Put them BCM43xx_SHM_SHARED, stating index 0x0120. 1123 + Keep in mind to update the count of keymacs in 0x003E as well! */ 1124 + } 1125 + } 1126 + } 1127 + 1128 + static int bcm43xx_key_write(struct bcm43xx_private *bcm, 1129 + u8 index, u8 algorithm, 1130 + const u8 *_key, int key_len, 1131 + const u8 *mac_addr) 1132 + { 1133 + u8 key[BCM43xx_SEC_KEYSIZE] = { 0 }; 1134 + 1135 + if (index >= ARRAY_SIZE(bcm->key)) 1136 + return -EINVAL; 1137 + if (key_len > ARRAY_SIZE(key)) 1138 + return -EINVAL; 1139 + if (algorithm < 1 || algorithm > 5) 1140 + return -EINVAL; 1141 + 1142 + memcpy(key, _key, key_len); 1143 + key_write(bcm, index, algorithm, (const u16 *)key); 1144 + keymac_write(bcm, index, (const u32 *)mac_addr); 1145 + 1146 + bcm->key[index].algorithm = algorithm; 1147 + 1148 + return 0; 1149 + } 1150 + 1151 + static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) 1152 + { 1153 + static const u32 zero_mac[2] = { 0 }; 1154 + unsigned int i,j, nr_keys = 54; 1155 + u16 offset; 1156 + 1157 + if (bcm->current_core->rev < 5) 1158 + nr_keys = 16; 1159 + assert(nr_keys <= ARRAY_SIZE(bcm->key)); 1160 + 1161 + for (i = 0; i < nr_keys; i++) { 1162 + bcm->key[i].enabled = 0; 1163 + /* returns for i < 4 immediately */ 1164 + keymac_write(bcm, i, zero_mac); 1165 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 1166 + 0x100 + (i * 2), 0x0000); 1167 + for (j = 0; j < 8; j++) { 1168 + offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE); 1169 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 1170 + offset, 0x0000); 1171 + } 1172 + } 1173 + dprintk(KERN_INFO PFX "Keys cleared\n"); 1174 + } 1175 + 1176 + /* Lowlevel core-switch function. This is only to be used in 1177 + * bcm43xx_switch_core() and bcm43xx_probe_cores() 1178 + */ 1179 + static int _switch_core(struct bcm43xx_private *bcm, int core) 1180 + { 1181 + int err; 1182 + int attempts = 0; 1183 + u32 current_core; 1184 + 1185 + assert(core >= 0); 1186 + while (1) { 1187 + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, 1188 + (core * 0x1000) + 0x18000000); 1189 + if (unlikely(err)) 1190 + goto error; 1191 + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, 1192 + &current_core); 1193 + if (unlikely(err)) 1194 + goto error; 1195 + current_core = (current_core - 0x18000000) / 0x1000; 1196 + if (current_core == core) 1197 + break; 1198 + 1199 + if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) 1200 + goto error; 1201 + udelay(10); 1202 + } 1203 + #ifdef CONFIG_BCM947XX 1204 + if (bcm->pci_dev->bus->number == 0) 1205 + bcm->current_core_offset = 0x1000 * core; 1206 + else 1207 + bcm->current_core_offset = 0; 1208 + #endif 1209 + 1210 + return 0; 1211 + error: 1212 + printk(KERN_ERR PFX "Failed to switch to core %d\n", core); 1213 + return -ENODEV; 1214 + } 1215 + 1216 + int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core) 1217 + { 1218 + int err; 1219 + 1220 + if (unlikely(!new_core)) 1221 + return 0; 1222 + if (!new_core->available) 1223 + return -ENODEV; 1224 + if (bcm->current_core == new_core) 1225 + return 0; 1226 + err = _switch_core(bcm, new_core->index); 1227 + if (unlikely(err)) 1228 + goto out; 1229 + 1230 + bcm->current_core = new_core; 1231 + bcm->current_80211_core_idx = -1; 1232 + if (new_core->id == BCM43xx_COREID_80211) 1233 + bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0])); 1234 + 1235 + out: 1236 + return err; 1237 + } 1238 + 1239 + static int bcm43xx_core_enabled(struct bcm43xx_private *bcm) 1240 + { 1241 + u32 value; 1242 + 1243 + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1244 + value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET 1245 + | BCM43xx_SBTMSTATELOW_REJECT; 1246 + 1247 + return (value == BCM43xx_SBTMSTATELOW_CLOCK); 1248 + } 1249 + 1250 + /* disable current core */ 1251 + static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags) 1252 + { 1253 + u32 sbtmstatelow; 1254 + u32 sbtmstatehigh; 1255 + int i; 1256 + 1257 + /* fetch sbtmstatelow from core information registers */ 1258 + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1259 + 1260 + /* core is already in reset */ 1261 + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET) 1262 + goto out; 1263 + 1264 + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) { 1265 + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | 1266 + BCM43xx_SBTMSTATELOW_REJECT; 1267 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1268 + 1269 + for (i = 0; i < 1000; i++) { 1270 + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1271 + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) { 1272 + i = -1; 1273 + break; 1274 + } 1275 + udelay(10); 1276 + } 1277 + if (i != -1) { 1278 + printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n"); 1279 + return -EBUSY; 1280 + } 1281 + 1282 + for (i = 0; i < 1000; i++) { 1283 + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); 1284 + if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) { 1285 + i = -1; 1286 + break; 1287 + } 1288 + udelay(10); 1289 + } 1290 + if (i != -1) { 1291 + printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n"); 1292 + return -EBUSY; 1293 + } 1294 + 1295 + sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | 1296 + BCM43xx_SBTMSTATELOW_REJECT | 1297 + BCM43xx_SBTMSTATELOW_RESET | 1298 + BCM43xx_SBTMSTATELOW_CLOCK | 1299 + core_flags; 1300 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1301 + udelay(10); 1302 + } 1303 + 1304 + sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET | 1305 + BCM43xx_SBTMSTATELOW_REJECT | 1306 + core_flags; 1307 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1308 + 1309 + out: 1310 + bcm->current_core->enabled = 0; 1311 + 1312 + return 0; 1313 + } 1314 + 1315 + /* enable (reset) current core */ 1316 + static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags) 1317 + { 1318 + u32 sbtmstatelow; 1319 + u32 sbtmstatehigh; 1320 + u32 sbimstate; 1321 + int err; 1322 + 1323 + err = bcm43xx_core_disable(bcm, core_flags); 1324 + if (err) 1325 + goto out; 1326 + 1327 + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | 1328 + BCM43xx_SBTMSTATELOW_RESET | 1329 + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | 1330 + core_flags; 1331 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1332 + udelay(1); 1333 + 1334 + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); 1335 + if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) { 1336 + sbtmstatehigh = 0x00000000; 1337 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh); 1338 + } 1339 + 1340 + sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE); 1341 + if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) { 1342 + sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT); 1343 + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate); 1344 + } 1345 + 1346 + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | 1347 + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | 1348 + core_flags; 1349 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1350 + udelay(1); 1351 + 1352 + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags; 1353 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1354 + udelay(1); 1355 + 1356 + bcm->current_core->enabled = 1; 1357 + assert(err == 0); 1358 + out: 1359 + return err; 1360 + } 1361 + 1362 + /* http://bcm-specs.sipsolutions.net/80211CoreReset */ 1363 + void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) 1364 + { 1365 + u32 flags = 0x00040000; 1366 + 1367 + if ((bcm43xx_core_enabled(bcm)) && 1368 + !bcm43xx_using_pio(bcm)) { 1369 + //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? 1370 + #ifndef CONFIG_BCM947XX 1371 + /* reset all used DMA controllers. */ 1372 + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); 1373 + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE); 1374 + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE); 1375 + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); 1376 + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); 1377 + if (bcm->current_core->rev < 5) 1378 + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); 1379 + #endif 1380 + } 1381 + if (bcm->shutting_down) { 1382 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 1383 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) 1384 + & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); 1385 + } else { 1386 + if (connect_phy) 1387 + flags |= 0x20000000; 1388 + bcm43xx_phy_connect(bcm, connect_phy); 1389 + bcm43xx_core_enable(bcm, flags); 1390 + bcm43xx_write16(bcm, 0x03E6, 0x0000); 1391 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 1392 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) 1393 + | BCM43xx_SBF_400); 1394 + } 1395 + } 1396 + 1397 + static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) 1398 + { 1399 + bcm43xx_radio_turn_off(bcm); 1400 + bcm43xx_write16(bcm, 0x03E6, 0x00F4); 1401 + bcm43xx_core_disable(bcm, 0); 1402 + } 1403 + 1404 + /* Mark the current 80211 core inactive. 1405 + * "active_80211_core" is the other 80211 core, which is used. 1406 + */ 1407 + static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, 1408 + struct bcm43xx_coreinfo *active_80211_core) 1409 + { 1410 + u32 sbtmstatelow; 1411 + struct bcm43xx_coreinfo *old_core; 1412 + int err = 0; 1413 + 1414 + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 1415 + bcm43xx_radio_turn_off(bcm); 1416 + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1417 + sbtmstatelow &= ~0x200a0000; 1418 + sbtmstatelow |= 0xa0000; 1419 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1420 + udelay(1); 1421 + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1422 + sbtmstatelow &= ~0xa0000; 1423 + sbtmstatelow |= 0x80000; 1424 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1425 + udelay(1); 1426 + 1427 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) { 1428 + old_core = bcm->current_core; 1429 + err = bcm43xx_switch_core(bcm, active_80211_core); 1430 + if (err) 1431 + goto out; 1432 + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1433 + sbtmstatelow &= ~0x20000000; 1434 + sbtmstatelow |= 0x20000000; 1435 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1436 + err = bcm43xx_switch_core(bcm, old_core); 1437 + } 1438 + 1439 + out: 1440 + return err; 1441 + } 1442 + 1443 + static void handle_irq_transmit_status(struct bcm43xx_private *bcm) 1444 + { 1445 + u32 v0, v1; 1446 + u16 tmp; 1447 + struct bcm43xx_xmitstatus stat; 1448 + 1449 + while (1) { 1450 + v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); 1451 + if (!v0) 1452 + break; 1453 + v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); 1454 + 1455 + stat.cookie = (v0 >> 16) & 0x0000FFFF; 1456 + tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1)); 1457 + stat.flags = tmp & 0xFF; 1458 + stat.cnt1 = (tmp & 0x0F00) >> 8; 1459 + stat.cnt2 = (tmp & 0xF000) >> 12; 1460 + stat.seq = (u16)(v1 & 0xFFFF); 1461 + stat.unknown = (u16)((v1 >> 16) & 0xFF); 1462 + 1463 + bcm43xx_debugfs_log_txstat(bcm, &stat); 1464 + 1465 + if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE) 1466 + continue; 1467 + if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) { 1468 + //TODO: packet was not acked (was lost) 1469 + } 1470 + //TODO: There are more (unknown) flags to test. see bcm43xx_main.h 1471 + 1472 + if (bcm43xx_using_pio(bcm)) 1473 + bcm43xx_pio_handle_xmitstatus(bcm, &stat); 1474 + else 1475 + bcm43xx_dma_handle_xmitstatus(bcm, &stat); 1476 + } 1477 + } 1478 + 1479 + static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) 1480 + { 1481 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); 1482 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); 1483 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, 1484 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); 1485 + assert(bcm->noisecalc.core_at_start == bcm->current_core); 1486 + assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel); 1487 + } 1488 + 1489 + static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) 1490 + { 1491 + /* Top half of Link Quality calculation. */ 1492 + 1493 + if (bcm->noisecalc.calculation_running) 1494 + return; 1495 + bcm->noisecalc.core_at_start = bcm->current_core; 1496 + bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel; 1497 + bcm->noisecalc.calculation_running = 1; 1498 + bcm->noisecalc.nr_samples = 0; 1499 + 1500 + bcm43xx_generate_noise_sample(bcm); 1501 + } 1502 + 1503 + static void handle_irq_noise(struct bcm43xx_private *bcm) 1504 + { 1505 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1506 + u16 tmp; 1507 + u8 noise[4]; 1508 + u8 i, j; 1509 + s32 average; 1510 + 1511 + /* Bottom half of Link Quality calculation. */ 1512 + 1513 + assert(bcm->noisecalc.calculation_running); 1514 + if (bcm->noisecalc.core_at_start != bcm->current_core || 1515 + bcm->noisecalc.channel_at_start != radio->channel) 1516 + goto drop_calculation; 1517 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408); 1518 + noise[0] = (tmp & 0x00FF); 1519 + noise[1] = (tmp & 0xFF00) >> 8; 1520 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A); 1521 + noise[2] = (tmp & 0x00FF); 1522 + noise[3] = (tmp & 0xFF00) >> 8; 1523 + if (noise[0] == 0x7F || noise[1] == 0x7F || 1524 + noise[2] == 0x7F || noise[3] == 0x7F) 1525 + goto generate_new; 1526 + 1527 + /* Get the noise samples. */ 1528 + assert(bcm->noisecalc.nr_samples <= 8); 1529 + i = bcm->noisecalc.nr_samples; 1530 + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); 1531 + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); 1532 + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); 1533 + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); 1534 + bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]]; 1535 + bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]]; 1536 + bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]]; 1537 + bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]]; 1538 + bcm->noisecalc.nr_samples++; 1539 + if (bcm->noisecalc.nr_samples == 8) { 1540 + /* Calculate the Link Quality by the noise samples. */ 1541 + average = 0; 1542 + for (i = 0; i < 8; i++) { 1543 + for (j = 0; j < 4; j++) 1544 + average += bcm->noisecalc.samples[i][j]; 1545 + } 1546 + average /= (8 * 4); 1547 + average *= 125; 1548 + average += 64; 1549 + average /= 128; 1550 + 1551 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); 1552 + tmp = (tmp / 128) & 0x1F; 1553 + if (tmp >= 8) 1554 + average += 2; 1555 + else 1556 + average -= 25; 1557 + if (tmp == 8) 1558 + average -= 72; 1559 + else 1560 + average -= 48; 1561 + 1562 + /* FIXME: This is wrong, but people want fancy stats. well... */ 1563 + bcm->stats.noise = average; 1564 + if (average > -65) 1565 + bcm->stats.link_quality = 0; 1566 + else if (average > -75) 1567 + bcm->stats.link_quality = 1; 1568 + else if (average > -85) 1569 + bcm->stats.link_quality = 2; 1570 + else 1571 + bcm->stats.link_quality = 3; 1572 + // dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average); 1573 + drop_calculation: 1574 + bcm->noisecalc.calculation_running = 0; 1575 + return; 1576 + } 1577 + generate_new: 1578 + bcm43xx_generate_noise_sample(bcm); 1579 + } 1580 + 1581 + static void handle_irq_ps(struct bcm43xx_private *bcm) 1582 + { 1583 + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { 1584 + ///TODO: PS TBTT 1585 + } else { 1586 + if (1/*FIXME: the last PSpoll frame was sent successfully */) 1587 + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); 1588 + } 1589 + if (bcm->ieee->iw_mode == IW_MODE_ADHOC) 1590 + bcm->reg124_set_0x4 = 1; 1591 + //FIXME else set to false? 1592 + } 1593 + 1594 + static void handle_irq_reg124(struct bcm43xx_private *bcm) 1595 + { 1596 + if (!bcm->reg124_set_0x4) 1597 + return; 1598 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, 1599 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) 1600 + | 0x4); 1601 + //FIXME: reset reg124_set_0x4 to false? 1602 + } 1603 + 1604 + static void handle_irq_pmq(struct bcm43xx_private *bcm) 1605 + { 1606 + u32 tmp; 1607 + 1608 + //TODO: AP mode. 1609 + 1610 + while (1) { 1611 + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS); 1612 + if (!(tmp & 0x00000008)) 1613 + break; 1614 + } 1615 + /* 16bit write is odd, but correct. */ 1616 + bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002); 1617 + } 1618 + 1619 + static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, 1620 + u16 ram_offset, u16 shm_size_offset) 1621 + { 1622 + u32 value; 1623 + u16 size = 0; 1624 + 1625 + /* Timestamp. */ 1626 + //FIXME: assumption: The chip sets the timestamp 1627 + value = 0; 1628 + bcm43xx_ram_write(bcm, ram_offset++, value); 1629 + bcm43xx_ram_write(bcm, ram_offset++, value); 1630 + size += 8; 1631 + 1632 + /* Beacon Interval / Capability Information */ 1633 + value = 0x0000;//FIXME: Which interval? 1634 + value |= (1 << 0) << 16; /* ESS */ 1635 + value |= (1 << 2) << 16; /* CF Pollable */ //FIXME? 1636 + value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME? 1637 + if (!bcm->ieee->open_wep) 1638 + value |= (1 << 4) << 16; /* Privacy */ 1639 + bcm43xx_ram_write(bcm, ram_offset++, value); 1640 + size += 4; 1641 + 1642 + /* SSID */ 1643 + //TODO 1644 + 1645 + /* FH Parameter Set */ 1646 + //TODO 1647 + 1648 + /* DS Parameter Set */ 1649 + //TODO 1650 + 1651 + /* CF Parameter Set */ 1652 + //TODO 1653 + 1654 + /* TIM */ 1655 + //TODO 1656 + 1657 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size); 1658 + } 1659 + 1660 + static void handle_irq_beacon(struct bcm43xx_private *bcm) 1661 + { 1662 + u32 status; 1663 + 1664 + bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON; 1665 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD); 1666 + 1667 + if ((status & 0x1) && (status & 0x2)) { 1668 + /* ACK beacon IRQ. */ 1669 + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 1670 + BCM43xx_IRQ_BEACON); 1671 + bcm->irq_savedstate |= BCM43xx_IRQ_BEACON; 1672 + return; 1673 + } 1674 + if (!(status & 0x1)) { 1675 + bcm43xx_generate_beacon_template(bcm, 0x68, 0x18); 1676 + status |= 0x1; 1677 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); 1678 + } 1679 + if (!(status & 0x2)) { 1680 + bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A); 1681 + status |= 0x2; 1682 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); 1683 + } 1684 + } 1685 + 1686 + /* Interrupt handler bottom-half */ 1687 + static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) 1688 + { 1689 + u32 reason; 1690 + u32 dma_reason[4]; 1691 + int activity = 0; 1692 + unsigned long flags; 1693 + 1694 + #ifdef CONFIG_BCM43XX_DEBUG 1695 + u32 _handled = 0x00000000; 1696 + # define bcmirq_handled(irq) do { _handled |= (irq); } while (0) 1697 + #else 1698 + # define bcmirq_handled(irq) do { /* nothing */ } while (0) 1699 + #endif /* CONFIG_BCM43XX_DEBUG*/ 1700 + 1701 + bcm43xx_lock_mmio(bcm, flags); 1702 + reason = bcm->irq_reason; 1703 + dma_reason[0] = bcm->dma_reason[0]; 1704 + dma_reason[1] = bcm->dma_reason[1]; 1705 + dma_reason[2] = bcm->dma_reason[2]; 1706 + dma_reason[3] = bcm->dma_reason[3]; 1707 + 1708 + if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) { 1709 + /* TX error. We get this when Template Ram is written in wrong endianess 1710 + * in dummy_tx(). We also get this if something is wrong with the TX header 1711 + * on DMA or PIO queues. 1712 + * Maybe we get this in other error conditions, too. 1713 + */ 1714 + printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n"); 1715 + bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); 1716 + } 1717 + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) | 1718 + (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) | 1719 + (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) | 1720 + (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) { 1721 + printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " 1722 + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", 1723 + dma_reason[0], dma_reason[1], 1724 + dma_reason[2], dma_reason[3]); 1725 + bcm43xx_controller_restart(bcm, "DMA error"); 1726 + bcm43xx_unlock_mmio(bcm, flags); 1727 + return; 1728 + } 1729 + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | 1730 + (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) | 1731 + (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) | 1732 + (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) { 1733 + printkl(KERN_ERR PFX "DMA error: " 1734 + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", 1735 + dma_reason[0], dma_reason[1], 1736 + dma_reason[2], dma_reason[3]); 1737 + } 1738 + 1739 + if (reason & BCM43xx_IRQ_PS) { 1740 + handle_irq_ps(bcm); 1741 + bcmirq_handled(BCM43xx_IRQ_PS); 1742 + } 1743 + 1744 + if (reason & BCM43xx_IRQ_REG124) { 1745 + handle_irq_reg124(bcm); 1746 + bcmirq_handled(BCM43xx_IRQ_REG124); 1747 + } 1748 + 1749 + if (reason & BCM43xx_IRQ_BEACON) { 1750 + if (bcm->ieee->iw_mode == IW_MODE_MASTER) 1751 + handle_irq_beacon(bcm); 1752 + bcmirq_handled(BCM43xx_IRQ_BEACON); 1753 + } 1754 + 1755 + if (reason & BCM43xx_IRQ_PMQ) { 1756 + handle_irq_pmq(bcm); 1757 + bcmirq_handled(BCM43xx_IRQ_PMQ); 1758 + } 1759 + 1760 + if (reason & BCM43xx_IRQ_SCAN) { 1761 + /*TODO*/ 1762 + //bcmirq_handled(BCM43xx_IRQ_SCAN); 1763 + } 1764 + 1765 + if (reason & BCM43xx_IRQ_NOISE) { 1766 + handle_irq_noise(bcm); 1767 + bcmirq_handled(BCM43xx_IRQ_NOISE); 1768 + } 1769 + 1770 + /* Check the DMA reason registers for received data. */ 1771 + assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); 1772 + assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); 1773 + if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { 1774 + if (bcm43xx_using_pio(bcm)) 1775 + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0); 1776 + else 1777 + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0); 1778 + /* We intentionally don't set "activity" to 1, here. */ 1779 + } 1780 + if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { 1781 + if (bcm43xx_using_pio(bcm)) 1782 + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3); 1783 + else 1784 + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1); 1785 + activity = 1; 1786 + } 1787 + bcmirq_handled(BCM43xx_IRQ_RX); 1788 + 1789 + if (reason & BCM43xx_IRQ_XMIT_STATUS) { 1790 + handle_irq_transmit_status(bcm); 1791 + activity = 1; 1792 + //TODO: In AP mode, this also causes sending of powersave responses. 1793 + bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); 1794 + } 1795 + 1796 + /* IRQ_PIO_WORKAROUND is handled in the top-half. */ 1797 + bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND); 1798 + #ifdef CONFIG_BCM43XX_DEBUG 1799 + if (unlikely(reason & ~_handled)) { 1800 + printkl(KERN_WARNING PFX 1801 + "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, " 1802 + "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", 1803 + reason, (reason & ~_handled), 1804 + dma_reason[0], dma_reason[1], 1805 + dma_reason[2], dma_reason[3]); 1806 + } 1807 + #endif 1808 + #undef bcmirq_handled 1809 + 1810 + if (!modparam_noleds) 1811 + bcm43xx_leds_update(bcm, activity); 1812 + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); 1813 + bcm43xx_unlock_mmio(bcm, flags); 1814 + } 1815 + 1816 + static void pio_irq_workaround(struct bcm43xx_private *bcm, 1817 + u16 base, int queueidx) 1818 + { 1819 + u16 rxctl; 1820 + 1821 + rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL); 1822 + if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE) 1823 + bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE; 1824 + else 1825 + bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE; 1826 + } 1827 + 1828 + static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason) 1829 + { 1830 + if (bcm43xx_using_pio(bcm) && 1831 + (bcm->current_core->rev < 3) && 1832 + (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { 1833 + /* Apply a PIO specific workaround to the dma_reasons */ 1834 + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0); 1835 + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1); 1836 + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2); 1837 + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3); 1838 + } 1839 + 1840 + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason); 1841 + 1842 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, 1843 + bcm->dma_reason[0]); 1844 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, 1845 + bcm->dma_reason[1]); 1846 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, 1847 + bcm->dma_reason[2]); 1848 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, 1849 + bcm->dma_reason[3]); 1850 + } 1851 + 1852 + /* Interrupt handler top-half */ 1853 + static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) 1854 + { 1855 + irqreturn_t ret = IRQ_HANDLED; 1856 + struct bcm43xx_private *bcm = dev_id; 1857 + u32 reason; 1858 + 1859 + if (!bcm) 1860 + return IRQ_NONE; 1861 + 1862 + spin_lock(&bcm->_lock); 1863 + 1864 + reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); 1865 + if (reason == 0xffffffff) { 1866 + /* irq not for us (shared irq) */ 1867 + ret = IRQ_NONE; 1868 + goto out; 1869 + } 1870 + reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); 1871 + if (!reason) 1872 + goto out; 1873 + 1874 + bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) 1875 + & 0x0001dc00; 1876 + bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) 1877 + & 0x0000dc00; 1878 + bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) 1879 + & 0x0000dc00; 1880 + bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) 1881 + & 0x0001dc00; 1882 + 1883 + bcm43xx_interrupt_ack(bcm, reason); 1884 + 1885 + /* Only accept IRQs, if we are initialized properly. 1886 + * This avoids an RX race while initializing. 1887 + * We should probably not enable IRQs before we are initialized 1888 + * completely, but some careful work is needed to fix this. I think it 1889 + * is best to stay with this cheap workaround for now... . 1890 + */ 1891 + if (likely(bcm->initialized)) { 1892 + /* disable all IRQs. They are enabled again in the bottom half. */ 1893 + bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 1894 + /* save the reason code and call our bottom half. */ 1895 + bcm->irq_reason = reason; 1896 + tasklet_schedule(&bcm->isr_tasklet); 1897 + } 1898 + 1899 + out: 1900 + mmiowb(); 1901 + spin_unlock(&bcm->_lock); 1902 + 1903 + return ret; 1904 + } 1905 + 1906 + static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) 1907 + { 1908 + if (bcm->firmware_norelease && !force) 1909 + return; /* Suspending or controller reset. */ 1910 + release_firmware(bcm->ucode); 1911 + bcm->ucode = NULL; 1912 + release_firmware(bcm->pcm); 1913 + bcm->pcm = NULL; 1914 + release_firmware(bcm->initvals0); 1915 + bcm->initvals0 = NULL; 1916 + release_firmware(bcm->initvals1); 1917 + bcm->initvals1 = NULL; 1918 + } 1919 + 1920 + static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) 1921 + { 1922 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1923 + u8 rev = bcm->current_core->rev; 1924 + int err = 0; 1925 + int nr; 1926 + char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; 1927 + 1928 + if (!bcm->ucode) { 1929 + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", 1930 + (rev >= 5 ? 5 : rev), 1931 + modparam_fwpostfix); 1932 + err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); 1933 + if (err) { 1934 + printk(KERN_ERR PFX 1935 + "Error: Microcode \"%s\" not available or load failed.\n", 1936 + buf); 1937 + goto error; 1938 + } 1939 + } 1940 + 1941 + if (!bcm->pcm) { 1942 + snprintf(buf, ARRAY_SIZE(buf), 1943 + "bcm43xx_pcm%d%s.fw", 1944 + (rev < 5 ? 4 : 5), 1945 + modparam_fwpostfix); 1946 + err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); 1947 + if (err) { 1948 + printk(KERN_ERR PFX 1949 + "Error: PCM \"%s\" not available or load failed.\n", 1950 + buf); 1951 + goto error; 1952 + } 1953 + } 1954 + 1955 + if (!bcm->initvals0) { 1956 + if (rev == 2 || rev == 4) { 1957 + switch (phy->type) { 1958 + case BCM43xx_PHYTYPE_A: 1959 + nr = 3; 1960 + break; 1961 + case BCM43xx_PHYTYPE_B: 1962 + case BCM43xx_PHYTYPE_G: 1963 + nr = 1; 1964 + break; 1965 + default: 1966 + goto err_noinitval; 1967 + } 1968 + 1969 + } else if (rev >= 5) { 1970 + switch (phy->type) { 1971 + case BCM43xx_PHYTYPE_A: 1972 + nr = 7; 1973 + break; 1974 + case BCM43xx_PHYTYPE_B: 1975 + case BCM43xx_PHYTYPE_G: 1976 + nr = 5; 1977 + break; 1978 + default: 1979 + goto err_noinitval; 1980 + } 1981 + } else 1982 + goto err_noinitval; 1983 + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", 1984 + nr, modparam_fwpostfix); 1985 + 1986 + err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); 1987 + if (err) { 1988 + printk(KERN_ERR PFX 1989 + "Error: InitVals \"%s\" not available or load failed.\n", 1990 + buf); 1991 + goto error; 1992 + } 1993 + if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { 1994 + printk(KERN_ERR PFX "InitVals fileformat error.\n"); 1995 + goto error; 1996 + } 1997 + } 1998 + 1999 + if (!bcm->initvals1) { 2000 + if (rev >= 5) { 2001 + u32 sbtmstatehigh; 2002 + 2003 + switch (phy->type) { 2004 + case BCM43xx_PHYTYPE_A: 2005 + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); 2006 + if (sbtmstatehigh & 0x00010000) 2007 + nr = 9; 2008 + else 2009 + nr = 10; 2010 + break; 2011 + case BCM43xx_PHYTYPE_B: 2012 + case BCM43xx_PHYTYPE_G: 2013 + nr = 6; 2014 + break; 2015 + default: 2016 + goto err_noinitval; 2017 + } 2018 + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", 2019 + nr, modparam_fwpostfix); 2020 + 2021 + err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); 2022 + if (err) { 2023 + printk(KERN_ERR PFX 2024 + "Error: InitVals \"%s\" not available or load failed.\n", 2025 + buf); 2026 + goto error; 2027 + } 2028 + if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { 2029 + printk(KERN_ERR PFX "InitVals fileformat error.\n"); 2030 + goto error; 2031 + } 2032 + } 2033 + } 2034 + 2035 + out: 2036 + return err; 2037 + error: 2038 + bcm43xx_release_firmware(bcm, 1); 2039 + goto out; 2040 + err_noinitval: 2041 + printk(KERN_ERR PFX "Error: No InitVals available!\n"); 2042 + err = -ENOENT; 2043 + goto error; 2044 + } 2045 + 2046 + static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) 2047 + { 2048 + const u32 *data; 2049 + unsigned int i, len; 2050 + 2051 + /* Upload Microcode. */ 2052 + data = (u32 *)(bcm->ucode->data); 2053 + len = bcm->ucode->size / sizeof(u32); 2054 + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); 2055 + for (i = 0; i < len; i++) { 2056 + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 2057 + be32_to_cpu(data[i])); 2058 + udelay(10); 2059 + } 2060 + 2061 + /* Upload PCM data. */ 2062 + data = (u32 *)(bcm->pcm->data); 2063 + len = bcm->pcm->size / sizeof(u32); 2064 + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); 2065 + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); 2066 + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); 2067 + for (i = 0; i < len; i++) { 2068 + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 2069 + be32_to_cpu(data[i])); 2070 + udelay(10); 2071 + } 2072 + } 2073 + 2074 + static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, 2075 + const struct bcm43xx_initval *data, 2076 + const unsigned int len) 2077 + { 2078 + u16 offset, size; 2079 + u32 value; 2080 + unsigned int i; 2081 + 2082 + for (i = 0; i < len; i++) { 2083 + offset = be16_to_cpu(data[i].offset); 2084 + size = be16_to_cpu(data[i].size); 2085 + value = be32_to_cpu(data[i].value); 2086 + 2087 + if (unlikely(offset >= 0x1000)) 2088 + goto err_format; 2089 + if (size == 2) { 2090 + if (unlikely(value & 0xFFFF0000)) 2091 + goto err_format; 2092 + bcm43xx_write16(bcm, offset, (u16)value); 2093 + } else if (size == 4) { 2094 + bcm43xx_write32(bcm, offset, value); 2095 + } else 2096 + goto err_format; 2097 + } 2098 + 2099 + return 0; 2100 + 2101 + err_format: 2102 + printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. " 2103 + "Please fix your bcm43xx firmware files.\n"); 2104 + return -EPROTO; 2105 + } 2106 + 2107 + static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) 2108 + { 2109 + int err; 2110 + 2111 + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, 2112 + bcm->initvals0->size / sizeof(struct bcm43xx_initval)); 2113 + if (err) 2114 + goto out; 2115 + if (bcm->initvals1) { 2116 + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, 2117 + bcm->initvals1->size / sizeof(struct bcm43xx_initval)); 2118 + if (err) 2119 + goto out; 2120 + } 2121 + out: 2122 + return err; 2123 + } 2124 + 2125 + static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) 2126 + { 2127 + int res; 2128 + unsigned int i; 2129 + u32 data; 2130 + 2131 + bcm->irq = bcm->pci_dev->irq; 2132 + #ifdef CONFIG_BCM947XX 2133 + if (bcm->pci_dev->bus->number == 0) { 2134 + struct pci_dev *d = NULL; 2135 + /* FIXME: we will probably need more device IDs here... */ 2136 + d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL); 2137 + if (d != NULL) { 2138 + bcm->irq = d->irq; 2139 + } 2140 + } 2141 + #endif 2142 + res = request_irq(bcm->irq, bcm43xx_interrupt_handler, 2143 + SA_SHIRQ, KBUILD_MODNAME, bcm); 2144 + if (res) { 2145 + printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); 2146 + return -ENODEV; 2147 + } 2148 + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); 2149 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); 2150 + i = 0; 2151 + while (1) { 2152 + data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); 2153 + if (data == BCM43xx_IRQ_READY) 2154 + break; 2155 + i++; 2156 + if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { 2157 + printk(KERN_ERR PFX "Card IRQ register not responding. " 2158 + "Giving up.\n"); 2159 + free_irq(bcm->irq, bcm); 2160 + return -ENODEV; 2161 + } 2162 + udelay(10); 2163 + } 2164 + // dummy read 2165 + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); 2166 + 2167 + return 0; 2168 + } 2169 + 2170 + /* Switch to the core used to write the GPIO register. 2171 + * This is either the ChipCommon, or the PCI core. 2172 + */ 2173 + static int switch_to_gpio_core(struct bcm43xx_private *bcm) 2174 + { 2175 + int err; 2176 + 2177 + /* Where to find the GPIO register depends on the chipset. 2178 + * If it has a ChipCommon, its register at offset 0x6c is the GPIO 2179 + * control register. Otherwise the register at offset 0x6c in the 2180 + * PCI core is the GPIO control register. 2181 + */ 2182 + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); 2183 + if (err == -ENODEV) { 2184 + err = bcm43xx_switch_core(bcm, &bcm->core_pci); 2185 + if (unlikely(err == -ENODEV)) { 2186 + printk(KERN_ERR PFX "gpio error: " 2187 + "Neither ChipCommon nor PCI core available!\n"); 2188 + } 2189 + } 2190 + 2191 + return err; 2192 + } 2193 + 2194 + /* Initialize the GPIOs 2195 + * http://bcm-specs.sipsolutions.net/GPIO 2196 + */ 2197 + static int bcm43xx_gpio_init(struct bcm43xx_private *bcm) 2198 + { 2199 + struct bcm43xx_coreinfo *old_core; 2200 + int err; 2201 + u32 mask, set; 2202 + 2203 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 2204 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) 2205 + & 0xFFFF3FFF); 2206 + 2207 + bcm43xx_leds_switch_all(bcm, 0); 2208 + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, 2209 + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); 2210 + 2211 + mask = 0x0000001F; 2212 + set = 0x0000000F; 2213 + if (bcm->chip_id == 0x4301) { 2214 + mask |= 0x0060; 2215 + set |= 0x0060; 2216 + } 2217 + if (0 /* FIXME: conditional unknown */) { 2218 + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, 2219 + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) 2220 + | 0x0100); 2221 + mask |= 0x0180; 2222 + set |= 0x0180; 2223 + } 2224 + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { 2225 + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, 2226 + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) 2227 + | 0x0200); 2228 + mask |= 0x0200; 2229 + set |= 0x0200; 2230 + } 2231 + if (bcm->current_core->rev >= 2) 2232 + mask |= 0x0010; /* FIXME: This is redundant. */ 2233 + 2234 + old_core = bcm->current_core; 2235 + err = switch_to_gpio_core(bcm); 2236 + if (err) 2237 + goto out; 2238 + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 2239 + (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set); 2240 + err = bcm43xx_switch_core(bcm, old_core); 2241 + out: 2242 + return err; 2243 + } 2244 + 2245 + /* Turn off all GPIO stuff. Call this on module unload, for example. */ 2246 + static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) 2247 + { 2248 + struct bcm43xx_coreinfo *old_core; 2249 + int err; 2250 + 2251 + old_core = bcm->current_core; 2252 + err = switch_to_gpio_core(bcm); 2253 + if (err) 2254 + return err; 2255 + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000); 2256 + err = bcm43xx_switch_core(bcm, old_core); 2257 + assert(err == 0); 2258 + 2259 + return 0; 2260 + } 2261 + 2262 + /* http://bcm-specs.sipsolutions.net/EnableMac */ 2263 + void bcm43xx_mac_enable(struct bcm43xx_private *bcm) 2264 + { 2265 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 2266 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) 2267 + | BCM43xx_SBF_MAC_ENABLED); 2268 + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); 2269 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ 2270 + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ 2271 + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); 2272 + } 2273 + 2274 + /* http://bcm-specs.sipsolutions.net/SuspendMAC */ 2275 + void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) 2276 + { 2277 + int i; 2278 + u32 tmp; 2279 + 2280 + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); 2281 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 2282 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) 2283 + & ~BCM43xx_SBF_MAC_ENABLED); 2284 + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ 2285 + for (i = 100000; i; i--) { 2286 + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); 2287 + if (tmp & BCM43xx_IRQ_READY) 2288 + return; 2289 + udelay(10); 2290 + } 2291 + printkl(KERN_ERR PFX "MAC suspend failed\n"); 2292 + } 2293 + 2294 + void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, 2295 + int iw_mode) 2296 + { 2297 + unsigned long flags; 2298 + struct net_device *net_dev = bcm->net_dev; 2299 + u32 status; 2300 + u16 value; 2301 + 2302 + spin_lock_irqsave(&bcm->ieee->lock, flags); 2303 + bcm->ieee->iw_mode = iw_mode; 2304 + spin_unlock_irqrestore(&bcm->ieee->lock, flags); 2305 + if (iw_mode == IW_MODE_MONITOR) 2306 + net_dev->type = ARPHRD_IEEE80211; 2307 + else 2308 + net_dev->type = ARPHRD_ETHER; 2309 + 2310 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 2311 + /* Reset status to infrastructured mode */ 2312 + status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); 2313 + status &= ~BCM43xx_SBF_MODE_PROMISC; 2314 + status |= BCM43xx_SBF_MODE_NOTADHOC; 2315 + 2316 + /* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */ 2317 + status |= BCM43xx_SBF_MODE_PROMISC; 2318 + 2319 + switch (iw_mode) { 2320 + case IW_MODE_MONITOR: 2321 + status |= BCM43xx_SBF_MODE_MONITOR; 2322 + status |= BCM43xx_SBF_MODE_PROMISC; 2323 + break; 2324 + case IW_MODE_ADHOC: 2325 + status &= ~BCM43xx_SBF_MODE_NOTADHOC; 2326 + break; 2327 + case IW_MODE_MASTER: 2328 + status |= BCM43xx_SBF_MODE_AP; 2329 + break; 2330 + case IW_MODE_SECOND: 2331 + case IW_MODE_REPEAT: 2332 + TODO(); /* TODO */ 2333 + break; 2334 + case IW_MODE_INFRA: 2335 + /* nothing to be done here... */ 2336 + break; 2337 + default: 2338 + dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode); 2339 + } 2340 + if (net_dev->flags & IFF_PROMISC) 2341 + status |= BCM43xx_SBF_MODE_PROMISC; 2342 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); 2343 + 2344 + value = 0x0002; 2345 + if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { 2346 + if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3) 2347 + value = 0x0064; 2348 + else 2349 + value = 0x0032; 2350 + } 2351 + bcm43xx_write16(bcm, 0x0612, value); 2352 + } 2353 + 2354 + /* This is the opposite of bcm43xx_chip_init() */ 2355 + static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) 2356 + { 2357 + bcm43xx_radio_turn_off(bcm); 2358 + if (!modparam_noleds) 2359 + bcm43xx_leds_exit(bcm); 2360 + bcm43xx_gpio_cleanup(bcm); 2361 + free_irq(bcm->irq, bcm); 2362 + bcm43xx_release_firmware(bcm, 0); 2363 + } 2364 + 2365 + /* Initialize the chip 2366 + * http://bcm-specs.sipsolutions.net/ChipInit 2367 + */ 2368 + static int bcm43xx_chip_init(struct bcm43xx_private *bcm) 2369 + { 2370 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 2371 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2372 + int err; 2373 + int tmp; 2374 + u32 value32; 2375 + u16 value16; 2376 + 2377 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 2378 + BCM43xx_SBF_CORE_READY 2379 + | BCM43xx_SBF_400); 2380 + 2381 + err = bcm43xx_request_firmware(bcm); 2382 + if (err) 2383 + goto out; 2384 + bcm43xx_upload_microcode(bcm); 2385 + 2386 + err = bcm43xx_initialize_irq(bcm); 2387 + if (err) 2388 + goto err_release_fw; 2389 + 2390 + err = bcm43xx_gpio_init(bcm); 2391 + if (err) 2392 + goto err_free_irq; 2393 + 2394 + err = bcm43xx_upload_initvals(bcm); 2395 + if (err) 2396 + goto err_gpio_cleanup; 2397 + bcm43xx_radio_turn_on(bcm); 2398 + 2399 + bcm43xx_write16(bcm, 0x03E6, 0x0000); 2400 + err = bcm43xx_phy_init(bcm); 2401 + if (err) 2402 + goto err_radio_off; 2403 + 2404 + /* Select initial Interference Mitigation. */ 2405 + tmp = radio->interfmode; 2406 + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; 2407 + bcm43xx_radio_set_interference_mitigation(bcm, tmp); 2408 + 2409 + bcm43xx_phy_set_antenna_diversity(bcm); 2410 + bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT); 2411 + if (phy->type == BCM43xx_PHYTYPE_B) { 2412 + value16 = bcm43xx_read16(bcm, 0x005E); 2413 + value16 |= 0x0004; 2414 + bcm43xx_write16(bcm, 0x005E, value16); 2415 + } 2416 + bcm43xx_write32(bcm, 0x0100, 0x01000000); 2417 + if (bcm->current_core->rev < 5) 2418 + bcm43xx_write32(bcm, 0x010C, 0x01000000); 2419 + 2420 + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 2421 + value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC; 2422 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); 2423 + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 2424 + value32 |= BCM43xx_SBF_MODE_NOTADHOC; 2425 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); 2426 + 2427 + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 2428 + value32 |= 0x100000; 2429 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); 2430 + 2431 + if (bcm43xx_using_pio(bcm)) { 2432 + bcm43xx_write32(bcm, 0x0210, 0x00000100); 2433 + bcm43xx_write32(bcm, 0x0230, 0x00000100); 2434 + bcm43xx_write32(bcm, 0x0250, 0x00000100); 2435 + bcm43xx_write32(bcm, 0x0270, 0x00000100); 2436 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000); 2437 + } 2438 + 2439 + /* Probe Response Timeout value */ 2440 + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ 2441 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); 2442 + 2443 + /* Initially set the wireless operation mode. */ 2444 + bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode); 2445 + 2446 + if (bcm->current_core->rev < 3) { 2447 + bcm43xx_write16(bcm, 0x060E, 0x0000); 2448 + bcm43xx_write16(bcm, 0x0610, 0x8000); 2449 + bcm43xx_write16(bcm, 0x0604, 0x0000); 2450 + bcm43xx_write16(bcm, 0x0606, 0x0200); 2451 + } else { 2452 + bcm43xx_write32(bcm, 0x0188, 0x80000000); 2453 + bcm43xx_write32(bcm, 0x018C, 0x02000000); 2454 + } 2455 + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000); 2456 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00); 2457 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00); 2458 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00); 2459 + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00); 2460 + 2461 + value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 2462 + value32 |= 0x00100000; 2463 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32); 2464 + 2465 + bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm)); 2466 + 2467 + assert(err == 0); 2468 + dprintk(KERN_INFO PFX "Chip initialized\n"); 2469 + out: 2470 + return err; 2471 + 2472 + err_radio_off: 2473 + bcm43xx_radio_turn_off(bcm); 2474 + err_gpio_cleanup: 2475 + bcm43xx_gpio_cleanup(bcm); 2476 + err_free_irq: 2477 + free_irq(bcm->irq, bcm); 2478 + err_release_fw: 2479 + bcm43xx_release_firmware(bcm, 1); 2480 + goto out; 2481 + } 2482 + 2483 + /* Validate chip access 2484 + * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ 2485 + static int bcm43xx_validate_chip(struct bcm43xx_private *bcm) 2486 + { 2487 + u32 value; 2488 + u32 shm_backup; 2489 + 2490 + shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000); 2491 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA); 2492 + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) 2493 + goto error; 2494 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55); 2495 + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) 2496 + goto error; 2497 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup); 2498 + 2499 + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 2500 + if ((value | 0x80000000) != 0x80000400) 2501 + goto error; 2502 + 2503 + value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); 2504 + if (value != 0x00000000) 2505 + goto error; 2506 + 2507 + return 0; 2508 + error: 2509 + printk(KERN_ERR PFX "Failed to validate the chipaccess\n"); 2510 + return -ENODEV; 2511 + } 2512 + 2513 + static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) 2514 + { 2515 + /* Initialize a "phyinfo" structure. The structure is already 2516 + * zeroed out. 2517 + */ 2518 + phy->antenna_diversity = 0xFFFF; 2519 + phy->savedpctlreg = 0xFFFF; 2520 + phy->minlowsig[0] = 0xFFFF; 2521 + phy->minlowsig[1] = 0xFFFF; 2522 + spin_lock_init(&phy->lock); 2523 + } 2524 + 2525 + static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) 2526 + { 2527 + /* Initialize a "radioinfo" structure. The structure is already 2528 + * zeroed out. 2529 + */ 2530 + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; 2531 + radio->channel = 0xFF; 2532 + radio->initial_channel = 0xFF; 2533 + radio->lofcal = 0xFFFF; 2534 + radio->initval = 0xFFFF; 2535 + radio->nrssi[0] = -1000; 2536 + radio->nrssi[1] = -1000; 2537 + } 2538 + 2539 + static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) 2540 + { 2541 + int err, i; 2542 + int current_core; 2543 + u32 core_vendor, core_id, core_rev; 2544 + u32 sb_id_hi, chip_id_32 = 0; 2545 + u16 pci_device, chip_id_16; 2546 + u8 core_count; 2547 + 2548 + memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo)); 2549 + memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo)); 2550 + memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo) 2551 + * BCM43xx_MAX_80211_CORES); 2552 + memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) 2553 + * BCM43xx_MAX_80211_CORES); 2554 + bcm->current_80211_core_idx = -1; 2555 + bcm->nr_80211_available = 0; 2556 + bcm->current_core = NULL; 2557 + bcm->active_80211_core = NULL; 2558 + 2559 + /* map core 0 */ 2560 + err = _switch_core(bcm, 0); 2561 + if (err) 2562 + goto out; 2563 + 2564 + /* fetch sb_id_hi from core information registers */ 2565 + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); 2566 + 2567 + core_id = (sb_id_hi & 0xFFF0) >> 4; 2568 + core_rev = (sb_id_hi & 0xF); 2569 + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; 2570 + 2571 + /* if present, chipcommon is always core 0; read the chipid from it */ 2572 + if (core_id == BCM43xx_COREID_CHIPCOMMON) { 2573 + chip_id_32 = bcm43xx_read32(bcm, 0); 2574 + chip_id_16 = chip_id_32 & 0xFFFF; 2575 + bcm->core_chipcommon.available = 1; 2576 + bcm->core_chipcommon.id = core_id; 2577 + bcm->core_chipcommon.rev = core_rev; 2578 + bcm->core_chipcommon.index = 0; 2579 + /* While we are at it, also read the capabilities. */ 2580 + bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES); 2581 + } else { 2582 + /* without a chipCommon, use a hard coded table. */ 2583 + pci_device = bcm->pci_dev->device; 2584 + if (pci_device == 0x4301) 2585 + chip_id_16 = 0x4301; 2586 + else if ((pci_device >= 0x4305) && (pci_device <= 0x4307)) 2587 + chip_id_16 = 0x4307; 2588 + else if ((pci_device >= 0x4402) && (pci_device <= 0x4403)) 2589 + chip_id_16 = 0x4402; 2590 + else if ((pci_device >= 0x4610) && (pci_device <= 0x4615)) 2591 + chip_id_16 = 0x4610; 2592 + else if ((pci_device >= 0x4710) && (pci_device <= 0x4715)) 2593 + chip_id_16 = 0x4710; 2594 + #ifdef CONFIG_BCM947XX 2595 + else if ((pci_device >= 0x4320) && (pci_device <= 0x4325)) 2596 + chip_id_16 = 0x4309; 2597 + #endif 2598 + else { 2599 + printk(KERN_ERR PFX "Could not determine Chip ID\n"); 2600 + return -ENODEV; 2601 + } 2602 + } 2603 + 2604 + /* ChipCommon with Core Rev >=4 encodes number of cores, 2605 + * otherwise consult hardcoded table */ 2606 + if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) { 2607 + core_count = (chip_id_32 & 0x0F000000) >> 24; 2608 + } else { 2609 + switch (chip_id_16) { 2610 + case 0x4610: 2611 + case 0x4704: 2612 + case 0x4710: 2613 + core_count = 9; 2614 + break; 2615 + case 0x4310: 2616 + core_count = 8; 2617 + break; 2618 + case 0x5365: 2619 + core_count = 7; 2620 + break; 2621 + case 0x4306: 2622 + core_count = 6; 2623 + break; 2624 + case 0x4301: 2625 + case 0x4307: 2626 + core_count = 5; 2627 + break; 2628 + case 0x4402: 2629 + core_count = 3; 2630 + break; 2631 + default: 2632 + /* SOL if we get here */ 2633 + assert(0); 2634 + core_count = 1; 2635 + } 2636 + } 2637 + 2638 + bcm->chip_id = chip_id_16; 2639 + bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16; 2640 + bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20; 2641 + 2642 + dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", 2643 + bcm->chip_id, bcm->chip_rev); 2644 + dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); 2645 + if (bcm->core_chipcommon.available) { 2646 + dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", 2647 + core_id, core_rev, core_vendor, 2648 + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled"); 2649 + } 2650 + 2651 + if (bcm->core_chipcommon.available) 2652 + current_core = 1; 2653 + else 2654 + current_core = 0; 2655 + for ( ; current_core < core_count; current_core++) { 2656 + struct bcm43xx_coreinfo *core; 2657 + struct bcm43xx_coreinfo_80211 *ext_80211; 2658 + 2659 + err = _switch_core(bcm, current_core); 2660 + if (err) 2661 + goto out; 2662 + /* Gather information */ 2663 + /* fetch sb_id_hi from core information registers */ 2664 + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); 2665 + 2666 + /* extract core_id, core_rev, core_vendor */ 2667 + core_id = (sb_id_hi & 0xFFF0) >> 4; 2668 + core_rev = (sb_id_hi & 0xF); 2669 + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; 2670 + 2671 + dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", 2672 + current_core, core_id, core_rev, core_vendor, 2673 + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" ); 2674 + 2675 + core = NULL; 2676 + switch (core_id) { 2677 + case BCM43xx_COREID_PCI: 2678 + core = &bcm->core_pci; 2679 + if (core->available) { 2680 + printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); 2681 + continue; 2682 + } 2683 + break; 2684 + case BCM43xx_COREID_80211: 2685 + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { 2686 + core = &(bcm->core_80211[i]); 2687 + ext_80211 = &(bcm->core_80211_ext[i]); 2688 + if (!core->available) 2689 + break; 2690 + core = NULL; 2691 + } 2692 + if (!core) { 2693 + printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n", 2694 + BCM43xx_MAX_80211_CORES); 2695 + continue; 2696 + } 2697 + if (i != 0) { 2698 + /* More than one 80211 core is only supported 2699 + * by special chips. 2700 + * There are chips with two 80211 cores, but with 2701 + * dangling pins on the second core. Be careful 2702 + * and ignore these cores here. 2703 + */ 2704 + if (bcm->pci_dev->device != 0x4324) { 2705 + dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n"); 2706 + continue; 2707 + } 2708 + } 2709 + switch (core_rev) { 2710 + case 2: 2711 + case 4: 2712 + case 5: 2713 + case 6: 2714 + case 7: 2715 + case 9: 2716 + break; 2717 + default: 2718 + printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n", 2719 + core_rev); 2720 + err = -ENODEV; 2721 + goto out; 2722 + } 2723 + bcm->nr_80211_available++; 2724 + bcm43xx_init_struct_phyinfo(&ext_80211->phy); 2725 + bcm43xx_init_struct_radioinfo(&ext_80211->radio); 2726 + break; 2727 + case BCM43xx_COREID_CHIPCOMMON: 2728 + printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n"); 2729 + break; 2730 + } 2731 + if (core) { 2732 + core->available = 1; 2733 + core->id = core_id; 2734 + core->rev = core_rev; 2735 + core->index = current_core; 2736 + } 2737 + } 2738 + 2739 + if (!bcm->core_80211[0].available) { 2740 + printk(KERN_ERR PFX "Error: No 80211 core found!\n"); 2741 + err = -ENODEV; 2742 + goto out; 2743 + } 2744 + 2745 + err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]); 2746 + 2747 + assert(err == 0); 2748 + out: 2749 + return err; 2750 + } 2751 + 2752 + static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm) 2753 + { 2754 + const u8 *mac = (const u8*)(bcm->net_dev->dev_addr); 2755 + u8 *bssid = bcm->ieee->bssid; 2756 + 2757 + switch (bcm->ieee->iw_mode) { 2758 + case IW_MODE_ADHOC: 2759 + random_ether_addr(bssid); 2760 + break; 2761 + case IW_MODE_MASTER: 2762 + case IW_MODE_INFRA: 2763 + case IW_MODE_REPEAT: 2764 + case IW_MODE_SECOND: 2765 + case IW_MODE_MONITOR: 2766 + memcpy(bssid, mac, ETH_ALEN); 2767 + break; 2768 + default: 2769 + assert(0); 2770 + } 2771 + } 2772 + 2773 + static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, 2774 + u16 rate, 2775 + int is_ofdm) 2776 + { 2777 + u16 offset; 2778 + 2779 + if (is_ofdm) { 2780 + offset = 0x480; 2781 + offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; 2782 + } 2783 + else { 2784 + offset = 0x4C0; 2785 + offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2; 2786 + } 2787 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20, 2788 + bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset)); 2789 + } 2790 + 2791 + static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm) 2792 + { 2793 + switch (bcm43xx_current_phy(bcm)->type) { 2794 + case BCM43xx_PHYTYPE_A: 2795 + case BCM43xx_PHYTYPE_G: 2796 + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1); 2797 + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1); 2798 + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1); 2799 + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1); 2800 + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1); 2801 + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1); 2802 + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1); 2803 + case BCM43xx_PHYTYPE_B: 2804 + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0); 2805 + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0); 2806 + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0); 2807 + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0); 2808 + break; 2809 + default: 2810 + assert(0); 2811 + } 2812 + } 2813 + 2814 + static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) 2815 + { 2816 + bcm43xx_chip_cleanup(bcm); 2817 + bcm43xx_pio_free(bcm); 2818 + bcm43xx_dma_free(bcm); 2819 + 2820 + bcm->current_core->initialized = 0; 2821 + } 2822 + 2823 + /* http://bcm-specs.sipsolutions.net/80211Init */ 2824 + static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) 2825 + { 2826 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2827 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 2828 + u32 ucodeflags; 2829 + int err; 2830 + u32 sbimconfiglow; 2831 + u8 limit; 2832 + 2833 + if (bcm->chip_rev < 5) { 2834 + sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); 2835 + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; 2836 + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; 2837 + if (bcm->bustype == BCM43xx_BUSTYPE_PCI) 2838 + sbimconfiglow |= 0x32; 2839 + else if (bcm->bustype == BCM43xx_BUSTYPE_SB) 2840 + sbimconfiglow |= 0x53; 2841 + else 2842 + assert(0); 2843 + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); 2844 + } 2845 + 2846 + bcm43xx_phy_calibrate(bcm); 2847 + err = bcm43xx_chip_init(bcm); 2848 + if (err) 2849 + goto out; 2850 + 2851 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev); 2852 + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET); 2853 + 2854 + if (0 /*FIXME: which condition has to be used here? */) 2855 + ucodeflags |= 0x00000010; 2856 + 2857 + /* HW decryption needs to be set now */ 2858 + ucodeflags |= 0x40000000; 2859 + 2860 + if (phy->type == BCM43xx_PHYTYPE_G) { 2861 + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; 2862 + if (phy->rev == 1) 2863 + ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY; 2864 + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) 2865 + ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL; 2866 + } else if (phy->type == BCM43xx_PHYTYPE_B) { 2867 + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; 2868 + if (phy->rev >= 2 && radio->version == 0x2050) 2869 + ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY; 2870 + } 2871 + 2872 + if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 2873 + BCM43xx_UCODEFLAGS_OFFSET)) { 2874 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 2875 + BCM43xx_UCODEFLAGS_OFFSET, ucodeflags); 2876 + } 2877 + 2878 + /* Short/Long Retry Limit. 2879 + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing 2880 + * the chip-internal counter. 2881 + */ 2882 + limit = limit_value(modparam_short_retry, 0, 0xF); 2883 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit); 2884 + limit = limit_value(modparam_long_retry, 0, 0xF); 2885 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit); 2886 + 2887 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3); 2888 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2); 2889 + 2890 + bcm43xx_rate_memory_init(bcm); 2891 + 2892 + /* Minimum Contention Window */ 2893 + if (phy->type == BCM43xx_PHYTYPE_B) 2894 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f); 2895 + else 2896 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f); 2897 + /* Maximum Contention Window */ 2898 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); 2899 + 2900 + bcm43xx_gen_bssid(bcm); 2901 + bcm43xx_write_mac_bssid_templates(bcm); 2902 + 2903 + if (bcm->current_core->rev >= 5) 2904 + bcm43xx_write16(bcm, 0x043C, 0x000C); 2905 + 2906 + if (bcm43xx_using_pio(bcm)) 2907 + err = bcm43xx_pio_init(bcm); 2908 + else 2909 + err = bcm43xx_dma_init(bcm); 2910 + if (err) 2911 + goto err_chip_cleanup; 2912 + bcm43xx_write16(bcm, 0x0612, 0x0050); 2913 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); 2914 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); 2915 + 2916 + bcm43xx_mac_enable(bcm); 2917 + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); 2918 + 2919 + bcm->current_core->initialized = 1; 2920 + out: 2921 + return err; 2922 + 2923 + err_chip_cleanup: 2924 + bcm43xx_chip_cleanup(bcm); 2925 + goto out; 2926 + } 2927 + 2928 + static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) 2929 + { 2930 + int err; 2931 + u16 pci_status; 2932 + 2933 + err = bcm43xx_pctl_set_crystal(bcm, 1); 2934 + if (err) 2935 + goto out; 2936 + bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); 2937 + bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); 2938 + 2939 + out: 2940 + return err; 2941 + } 2942 + 2943 + static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm) 2944 + { 2945 + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); 2946 + bcm43xx_pctl_set_crystal(bcm, 0); 2947 + } 2948 + 2949 + static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, 2950 + u32 address, 2951 + u32 data) 2952 + { 2953 + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address); 2954 + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data); 2955 + } 2956 + 2957 + static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm) 2958 + { 2959 + int err; 2960 + struct bcm43xx_coreinfo *old_core; 2961 + 2962 + old_core = bcm->current_core; 2963 + err = bcm43xx_switch_core(bcm, &bcm->core_pci); 2964 + if (err) 2965 + goto out; 2966 + 2967 + bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); 2968 + 2969 + bcm43xx_switch_core(bcm, old_core); 2970 + assert(err == 0); 2971 + out: 2972 + return err; 2973 + } 2974 + 2975 + /* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable. 2976 + * To enable core 0, pass a core_mask of 1<<0 2977 + */ 2978 + static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, 2979 + u32 core_mask) 2980 + { 2981 + u32 backplane_flag_nr; 2982 + u32 value; 2983 + struct bcm43xx_coreinfo *old_core; 2984 + int err = 0; 2985 + 2986 + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG); 2987 + backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK; 2988 + 2989 + old_core = bcm->current_core; 2990 + err = bcm43xx_switch_core(bcm, &bcm->core_pci); 2991 + if (err) 2992 + goto out; 2993 + 2994 + if (bcm->core_pci.rev < 6) { 2995 + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC); 2996 + value |= (1 << backplane_flag_nr); 2997 + bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value); 2998 + } else { 2999 + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value); 3000 + if (err) { 3001 + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); 3002 + goto out_switch_back; 3003 + } 3004 + value |= core_mask << 8; 3005 + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value); 3006 + if (err) { 3007 + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); 3008 + goto out_switch_back; 3009 + } 3010 + } 3011 + 3012 + value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); 3013 + value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; 3014 + bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); 3015 + 3016 + if (bcm->core_pci.rev < 5) { 3017 + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); 3018 + value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) 3019 + & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; 3020 + value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT) 3021 + & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; 3022 + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); 3023 + err = bcm43xx_pcicore_commit_settings(bcm); 3024 + assert(err == 0); 3025 + } 3026 + 3027 + out_switch_back: 3028 + err = bcm43xx_switch_core(bcm, old_core); 3029 + out: 3030 + return err; 3031 + } 3032 + 3033 + static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) 3034 + { 3035 + ieee80211softmac_start(bcm->net_dev); 3036 + } 3037 + 3038 + static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) 3039 + { 3040 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 3041 + 3042 + if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2) 3043 + return; 3044 + 3045 + bcm43xx_mac_suspend(bcm); 3046 + bcm43xx_phy_lo_g_measure(bcm); 3047 + bcm43xx_mac_enable(bcm); 3048 + } 3049 + 3050 + static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm) 3051 + { 3052 + bcm43xx_phy_lo_mark_all_unused(bcm); 3053 + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { 3054 + bcm43xx_mac_suspend(bcm); 3055 + bcm43xx_calc_nrssi_slope(bcm); 3056 + bcm43xx_mac_enable(bcm); 3057 + } 3058 + } 3059 + 3060 + static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) 3061 + { 3062 + /* Update device statistics. */ 3063 + bcm43xx_calculate_link_quality(bcm); 3064 + } 3065 + 3066 + static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) 3067 + { 3068 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 3069 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 3070 + 3071 + if (phy->type == BCM43xx_PHYTYPE_G) { 3072 + //TODO: update_aci_moving_average 3073 + if (radio->aci_enable && radio->aci_wlan_automatic) { 3074 + bcm43xx_mac_suspend(bcm); 3075 + if (!radio->aci_enable && 1 /*TODO: not scanning? */) { 3076 + if (0 /*TODO: bunch of conditions*/) { 3077 + bcm43xx_radio_set_interference_mitigation(bcm, 3078 + BCM43xx_RADIO_INTERFMODE_MANUALWLAN); 3079 + } 3080 + } else if (1/*TODO*/) { 3081 + /* 3082 + if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) { 3083 + bcm43xx_radio_set_interference_mitigation(bcm, 3084 + BCM43xx_RADIO_INTERFMODE_NONE); 3085 + } 3086 + */ 3087 + } 3088 + bcm43xx_mac_enable(bcm); 3089 + } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN && 3090 + phy->rev == 1) { 3091 + //TODO: implement rev1 workaround 3092 + } 3093 + } 3094 + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? 3095 + //TODO for APHY (temperature?) 3096 + } 3097 + 3098 + static void bcm43xx_periodic_task_handler(unsigned long d) 3099 + { 3100 + struct bcm43xx_private *bcm = (struct bcm43xx_private *)d; 3101 + unsigned long flags; 3102 + unsigned int state; 3103 + 3104 + bcm43xx_lock_mmio(bcm, flags); 3105 + 3106 + assert(bcm->initialized); 3107 + state = bcm->periodic_state; 3108 + if (state % 8 == 0) 3109 + bcm43xx_periodic_every120sec(bcm); 3110 + if (state % 4 == 0) 3111 + bcm43xx_periodic_every60sec(bcm); 3112 + if (state % 2 == 0) 3113 + bcm43xx_periodic_every30sec(bcm); 3114 + bcm43xx_periodic_every15sec(bcm); 3115 + bcm->periodic_state = state + 1; 3116 + 3117 + mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); 3118 + 3119 + bcm43xx_unlock_mmio(bcm, flags); 3120 + } 3121 + 3122 + static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) 3123 + { 3124 + del_timer_sync(&bcm->periodic_tasks); 3125 + } 3126 + 3127 + static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) 3128 + { 3129 + struct timer_list *timer = &(bcm->periodic_tasks); 3130 + 3131 + assert(bcm->initialized); 3132 + setup_timer(timer, 3133 + bcm43xx_periodic_task_handler, 3134 + (unsigned long)bcm); 3135 + timer->expires = jiffies; 3136 + add_timer(timer); 3137 + } 3138 + 3139 + static void bcm43xx_security_init(struct bcm43xx_private *bcm) 3140 + { 3141 + bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 3142 + 0x0056) * 2; 3143 + bcm43xx_clear_keys(bcm); 3144 + } 3145 + 3146 + /* This is the opposite of bcm43xx_init_board() */ 3147 + static void bcm43xx_free_board(struct bcm43xx_private *bcm) 3148 + { 3149 + int i, err; 3150 + unsigned long flags; 3151 + 3152 + bcm43xx_sysfs_unregister(bcm); 3153 + 3154 + bcm43xx_periodic_tasks_delete(bcm); 3155 + 3156 + bcm43xx_lock(bcm, flags); 3157 + bcm->initialized = 0; 3158 + bcm->shutting_down = 1; 3159 + bcm43xx_unlock(bcm, flags); 3160 + 3161 + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { 3162 + if (!bcm->core_80211[i].available) 3163 + continue; 3164 + if (!bcm->core_80211[i].initialized) 3165 + continue; 3166 + 3167 + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); 3168 + assert(err == 0); 3169 + bcm43xx_wireless_core_cleanup(bcm); 3170 + } 3171 + 3172 + bcm43xx_pctl_set_crystal(bcm, 0); 3173 + 3174 + bcm43xx_lock(bcm, flags); 3175 + bcm->shutting_down = 0; 3176 + bcm43xx_unlock(bcm, flags); 3177 + } 3178 + 3179 + static int bcm43xx_init_board(struct bcm43xx_private *bcm) 3180 + { 3181 + int i, err; 3182 + int connect_phy; 3183 + unsigned long flags; 3184 + 3185 + might_sleep(); 3186 + 3187 + bcm43xx_lock(bcm, flags); 3188 + bcm->initialized = 0; 3189 + bcm->shutting_down = 0; 3190 + bcm43xx_unlock(bcm, flags); 3191 + 3192 + err = bcm43xx_pctl_set_crystal(bcm, 1); 3193 + if (err) 3194 + goto out; 3195 + err = bcm43xx_pctl_init(bcm); 3196 + if (err) 3197 + goto err_crystal_off; 3198 + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); 3199 + if (err) 3200 + goto err_crystal_off; 3201 + 3202 + tasklet_enable(&bcm->isr_tasklet); 3203 + for (i = 0; i < bcm->nr_80211_available; i++) { 3204 + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); 3205 + assert(err != -ENODEV); 3206 + if (err) 3207 + goto err_80211_unwind; 3208 + 3209 + /* Enable the selected wireless core. 3210 + * Connect PHY only on the first core. 3211 + */ 3212 + if (!bcm43xx_core_enabled(bcm)) { 3213 + if (bcm->nr_80211_available == 1) { 3214 + connect_phy = bcm43xx_current_phy(bcm)->connected; 3215 + } else { 3216 + if (i == 0) 3217 + connect_phy = 1; 3218 + else 3219 + connect_phy = 0; 3220 + } 3221 + bcm43xx_wireless_core_reset(bcm, connect_phy); 3222 + } 3223 + 3224 + if (i != 0) 3225 + bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); 3226 + 3227 + err = bcm43xx_wireless_core_init(bcm); 3228 + if (err) 3229 + goto err_80211_unwind; 3230 + 3231 + if (i != 0) { 3232 + bcm43xx_mac_suspend(bcm); 3233 + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 3234 + bcm43xx_radio_turn_off(bcm); 3235 + } 3236 + } 3237 + bcm->active_80211_core = &bcm->core_80211[0]; 3238 + if (bcm->nr_80211_available >= 2) { 3239 + bcm43xx_switch_core(bcm, &bcm->core_80211[0]); 3240 + bcm43xx_mac_enable(bcm); 3241 + } 3242 + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); 3243 + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); 3244 + dprintk(KERN_INFO PFX "80211 cores initialized\n"); 3245 + bcm43xx_security_init(bcm); 3246 + bcm43xx_softmac_init(bcm); 3247 + 3248 + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); 3249 + 3250 + if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { 3251 + bcm43xx_mac_suspend(bcm); 3252 + bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); 3253 + bcm43xx_mac_enable(bcm); 3254 + } 3255 + 3256 + /* Initialization of the board is done. Flag it as such. */ 3257 + bcm43xx_lock(bcm, flags); 3258 + bcm->initialized = 1; 3259 + bcm43xx_unlock(bcm, flags); 3260 + 3261 + bcm43xx_periodic_tasks_setup(bcm); 3262 + bcm43xx_sysfs_register(bcm); 3263 + //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... 3264 + 3265 + assert(err == 0); 3266 + out: 3267 + return err; 3268 + 3269 + err_80211_unwind: 3270 + tasklet_disable(&bcm->isr_tasklet); 3271 + /* unwind all 80211 initialization */ 3272 + for (i = 0; i < bcm->nr_80211_available; i++) { 3273 + if (!bcm->core_80211[i].initialized) 3274 + continue; 3275 + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 3276 + bcm43xx_wireless_core_cleanup(bcm); 3277 + } 3278 + err_crystal_off: 3279 + bcm43xx_pctl_set_crystal(bcm, 0); 3280 + goto out; 3281 + } 3282 + 3283 + static void bcm43xx_detach_board(struct bcm43xx_private *bcm) 3284 + { 3285 + struct pci_dev *pci_dev = bcm->pci_dev; 3286 + int i; 3287 + 3288 + bcm43xx_chipset_detach(bcm); 3289 + /* Do _not_ access the chip, after it is detached. */ 3290 + iounmap(bcm->mmio_addr); 3291 + 3292 + pci_release_regions(pci_dev); 3293 + pci_disable_device(pci_dev); 3294 + 3295 + /* Free allocated structures/fields */ 3296 + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { 3297 + kfree(bcm->core_80211_ext[i].phy._lo_pairs); 3298 + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) 3299 + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); 3300 + } 3301 + } 3302 + 3303 + static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) 3304 + { 3305 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 3306 + u16 value; 3307 + u8 phy_version; 3308 + u8 phy_type; 3309 + u8 phy_rev; 3310 + int phy_rev_ok = 1; 3311 + void *p; 3312 + 3313 + value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); 3314 + 3315 + phy_version = (value & 0xF000) >> 12; 3316 + phy_type = (value & 0x0F00) >> 8; 3317 + phy_rev = (value & 0x000F); 3318 + 3319 + dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n", 3320 + phy_version, phy_type, phy_rev); 3321 + 3322 + switch (phy_type) { 3323 + case BCM43xx_PHYTYPE_A: 3324 + if (phy_rev >= 4) 3325 + phy_rev_ok = 0; 3326 + /*FIXME: We need to switch the ieee->modulation, etc.. flags, 3327 + * if we switch 80211 cores after init is done. 3328 + * As we do not implement on the fly switching between 3329 + * wireless cores, I will leave this as a future task. 3330 + */ 3331 + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION; 3332 + bcm->ieee->mode = IEEE_A; 3333 + bcm->ieee->freq_band = IEEE80211_52GHZ_BAND | 3334 + IEEE80211_24GHZ_BAND; 3335 + break; 3336 + case BCM43xx_PHYTYPE_B: 3337 + if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7) 3338 + phy_rev_ok = 0; 3339 + bcm->ieee->modulation = IEEE80211_CCK_MODULATION; 3340 + bcm->ieee->mode = IEEE_B; 3341 + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; 3342 + break; 3343 + case BCM43xx_PHYTYPE_G: 3344 + if (phy_rev > 7) 3345 + phy_rev_ok = 0; 3346 + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION | 3347 + IEEE80211_CCK_MODULATION; 3348 + bcm->ieee->mode = IEEE_G; 3349 + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; 3350 + break; 3351 + default: 3352 + printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n", 3353 + phy_type); 3354 + return -ENODEV; 3355 + }; 3356 + if (!phy_rev_ok) { 3357 + printk(KERN_WARNING PFX "Invalid PHY Revision %x\n", 3358 + phy_rev); 3359 + } 3360 + 3361 + phy->version = phy_version; 3362 + phy->type = phy_type; 3363 + phy->rev = phy_rev; 3364 + if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { 3365 + p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT, 3366 + GFP_KERNEL); 3367 + if (!p) 3368 + return -ENOMEM; 3369 + phy->_lo_pairs = p; 3370 + } 3371 + 3372 + return 0; 3373 + } 3374 + 3375 + static int bcm43xx_attach_board(struct bcm43xx_private *bcm) 3376 + { 3377 + struct pci_dev *pci_dev = bcm->pci_dev; 3378 + struct net_device *net_dev = bcm->net_dev; 3379 + int err; 3380 + int i; 3381 + unsigned long mmio_start, mmio_flags, mmio_len; 3382 + u32 coremask; 3383 + 3384 + err = pci_enable_device(pci_dev); 3385 + if (err) { 3386 + printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err); 3387 + goto out; 3388 + } 3389 + mmio_start = pci_resource_start(pci_dev, 0); 3390 + mmio_flags = pci_resource_flags(pci_dev, 0); 3391 + mmio_len = pci_resource_len(pci_dev, 0); 3392 + if (!(mmio_flags & IORESOURCE_MEM)) { 3393 + printk(KERN_ERR PFX 3394 + "%s, region #0 not an MMIO resource, aborting\n", 3395 + pci_name(pci_dev)); 3396 + err = -ENODEV; 3397 + goto err_pci_disable; 3398 + } 3399 + err = pci_request_regions(pci_dev, KBUILD_MODNAME); 3400 + if (err) { 3401 + printk(KERN_ERR PFX 3402 + "could not access PCI resources (%i)\n", err); 3403 + goto err_pci_disable; 3404 + } 3405 + /* enable PCI bus-mastering */ 3406 + pci_set_master(pci_dev); 3407 + bcm->mmio_addr = ioremap(mmio_start, mmio_len); 3408 + if (!bcm->mmio_addr) { 3409 + printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", 3410 + pci_name(pci_dev)); 3411 + err = -EIO; 3412 + goto err_pci_release; 3413 + } 3414 + bcm->mmio_len = mmio_len; 3415 + net_dev->base_addr = (unsigned long)bcm->mmio_addr; 3416 + 3417 + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, 3418 + &bcm->board_vendor); 3419 + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, 3420 + &bcm->board_type); 3421 + bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, 3422 + &bcm->board_revision); 3423 + 3424 + err = bcm43xx_chipset_attach(bcm); 3425 + if (err) 3426 + goto err_iounmap; 3427 + err = bcm43xx_pctl_init(bcm); 3428 + if (err) 3429 + goto err_chipset_detach; 3430 + err = bcm43xx_probe_cores(bcm); 3431 + if (err) 3432 + goto err_chipset_detach; 3433 + 3434 + /* Attach all IO cores to the backplane. */ 3435 + coremask = 0; 3436 + for (i = 0; i < bcm->nr_80211_available; i++) 3437 + coremask |= (1 << bcm->core_80211[i].index); 3438 + //FIXME: Also attach some non80211 cores? 3439 + err = bcm43xx_setup_backplane_pci_connection(bcm, coremask); 3440 + if (err) { 3441 + printk(KERN_ERR PFX "Backplane->PCI connection failed!\n"); 3442 + goto err_chipset_detach; 3443 + } 3444 + 3445 + err = bcm43xx_sprom_extract(bcm); 3446 + if (err) 3447 + goto err_chipset_detach; 3448 + err = bcm43xx_leds_init(bcm); 3449 + if (err) 3450 + goto err_chipset_detach; 3451 + 3452 + for (i = 0; i < bcm->nr_80211_available; i++) { 3453 + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); 3454 + assert(err != -ENODEV); 3455 + if (err) 3456 + goto err_80211_unwind; 3457 + 3458 + /* Enable the selected wireless core. 3459 + * Connect PHY only on the first core. 3460 + */ 3461 + bcm43xx_wireless_core_reset(bcm, (i == 0)); 3462 + 3463 + err = bcm43xx_read_phyinfo(bcm); 3464 + if (err && (i == 0)) 3465 + goto err_80211_unwind; 3466 + 3467 + err = bcm43xx_read_radioinfo(bcm); 3468 + if (err && (i == 0)) 3469 + goto err_80211_unwind; 3470 + 3471 + err = bcm43xx_validate_chip(bcm); 3472 + if (err && (i == 0)) 3473 + goto err_80211_unwind; 3474 + 3475 + bcm43xx_radio_turn_off(bcm); 3476 + err = bcm43xx_phy_init_tssi2dbm_table(bcm); 3477 + if (err) 3478 + goto err_80211_unwind; 3479 + bcm43xx_wireless_core_disable(bcm); 3480 + } 3481 + bcm43xx_pctl_set_crystal(bcm, 0); 3482 + 3483 + /* Set the MAC address in the networking subsystem */ 3484 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) 3485 + memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); 3486 + else 3487 + memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); 3488 + 3489 + bcm43xx_geo_init(bcm); 3490 + 3491 + snprintf(bcm->nick, IW_ESSID_MAX_SIZE, 3492 + "Broadcom %04X", bcm->chip_id); 3493 + 3494 + assert(err == 0); 3495 + out: 3496 + return err; 3497 + 3498 + err_80211_unwind: 3499 + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { 3500 + kfree(bcm->core_80211_ext[i].phy._lo_pairs); 3501 + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) 3502 + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); 3503 + } 3504 + err_chipset_detach: 3505 + bcm43xx_chipset_detach(bcm); 3506 + err_iounmap: 3507 + iounmap(bcm->mmio_addr); 3508 + err_pci_release: 3509 + pci_release_regions(pci_dev); 3510 + err_pci_disable: 3511 + pci_disable_device(pci_dev); 3512 + goto out; 3513 + } 3514 + 3515 + /* Do the Hardware IO operations to send the txb */ 3516 + static inline int bcm43xx_tx(struct bcm43xx_private *bcm, 3517 + struct ieee80211_txb *txb) 3518 + { 3519 + int err = -ENODEV; 3520 + 3521 + if (bcm43xx_using_pio(bcm)) 3522 + err = bcm43xx_pio_tx(bcm, txb); 3523 + else 3524 + err = bcm43xx_dma_tx(bcm, txb); 3525 + 3526 + return err; 3527 + } 3528 + 3529 + static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, 3530 + u8 channel) 3531 + { 3532 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3533 + struct bcm43xx_radioinfo *radio; 3534 + unsigned long flags; 3535 + 3536 + bcm43xx_lock_mmio(bcm, flags); 3537 + if (bcm->initialized) { 3538 + bcm43xx_mac_suspend(bcm); 3539 + bcm43xx_radio_selectchannel(bcm, channel, 0); 3540 + bcm43xx_mac_enable(bcm); 3541 + } else { 3542 + radio = bcm43xx_current_radio(bcm); 3543 + radio->initial_channel = channel; 3544 + } 3545 + bcm43xx_unlock_mmio(bcm, flags); 3546 + } 3547 + 3548 + /* set_security() callback in struct ieee80211_device */ 3549 + static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, 3550 + struct ieee80211_security *sec) 3551 + { 3552 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3553 + struct ieee80211_security *secinfo = &bcm->ieee->sec; 3554 + unsigned long flags; 3555 + int keyidx; 3556 + 3557 + dprintk(KERN_INFO PFX "set security called\n"); 3558 + 3559 + bcm43xx_lock_mmio(bcm, flags); 3560 + 3561 + for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) 3562 + if (sec->flags & (1<<keyidx)) { 3563 + secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx]; 3564 + secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; 3565 + memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN); 3566 + } 3567 + 3568 + if (sec->flags & SEC_ACTIVE_KEY) { 3569 + secinfo->active_key = sec->active_key; 3570 + dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key); 3571 + } 3572 + if (sec->flags & SEC_UNICAST_GROUP) { 3573 + secinfo->unicast_uses_group = sec->unicast_uses_group; 3574 + dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group); 3575 + } 3576 + if (sec->flags & SEC_LEVEL) { 3577 + secinfo->level = sec->level; 3578 + dprintk(KERN_INFO PFX " .level = %d\n", sec->level); 3579 + } 3580 + if (sec->flags & SEC_ENABLED) { 3581 + secinfo->enabled = sec->enabled; 3582 + dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled); 3583 + } 3584 + if (sec->flags & SEC_ENCRYPT) { 3585 + secinfo->encrypt = sec->encrypt; 3586 + dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt); 3587 + } 3588 + if (bcm->initialized && !bcm->ieee->host_encrypt) { 3589 + if (secinfo->enabled) { 3590 + /* upload WEP keys to hardware */ 3591 + char null_address[6] = { 0 }; 3592 + u8 algorithm = 0; 3593 + for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) { 3594 + if (!(sec->flags & (1<<keyidx))) 3595 + continue; 3596 + switch (sec->encode_alg[keyidx]) { 3597 + case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break; 3598 + case SEC_ALG_WEP: 3599 + algorithm = BCM43xx_SEC_ALGO_WEP; 3600 + if (secinfo->key_sizes[keyidx] == 13) 3601 + algorithm = BCM43xx_SEC_ALGO_WEP104; 3602 + break; 3603 + case SEC_ALG_TKIP: 3604 + FIXME(); 3605 + algorithm = BCM43xx_SEC_ALGO_TKIP; 3606 + break; 3607 + case SEC_ALG_CCMP: 3608 + FIXME(); 3609 + algorithm = BCM43xx_SEC_ALGO_AES; 3610 + break; 3611 + default: 3612 + assert(0); 3613 + break; 3614 + } 3615 + bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]); 3616 + bcm->key[keyidx].enabled = 1; 3617 + bcm->key[keyidx].algorithm = algorithm; 3618 + } 3619 + } else 3620 + bcm43xx_clear_keys(bcm); 3621 + } 3622 + bcm43xx_unlock_mmio(bcm, flags); 3623 + } 3624 + 3625 + /* hard_start_xmit() callback in struct ieee80211_device */ 3626 + static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, 3627 + struct net_device *net_dev, 3628 + int pri) 3629 + { 3630 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3631 + int err = -ENODEV; 3632 + unsigned long flags; 3633 + 3634 + bcm43xx_lock_mmio(bcm, flags); 3635 + if (likely(bcm->initialized)) 3636 + err = bcm43xx_tx(bcm, txb); 3637 + bcm43xx_unlock_mmio(bcm, flags); 3638 + 3639 + return err; 3640 + } 3641 + 3642 + static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev) 3643 + { 3644 + return &(bcm43xx_priv(net_dev)->ieee->stats); 3645 + } 3646 + 3647 + static void bcm43xx_net_tx_timeout(struct net_device *net_dev) 3648 + { 3649 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3650 + unsigned long flags; 3651 + 3652 + bcm43xx_lock_mmio(bcm, flags); 3653 + bcm43xx_controller_restart(bcm, "TX timeout"); 3654 + bcm43xx_unlock_mmio(bcm, flags); 3655 + } 3656 + 3657 + #ifdef CONFIG_NET_POLL_CONTROLLER 3658 + static void bcm43xx_net_poll_controller(struct net_device *net_dev) 3659 + { 3660 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3661 + unsigned long flags; 3662 + 3663 + local_irq_save(flags); 3664 + bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); 3665 + local_irq_restore(flags); 3666 + } 3667 + #endif /* CONFIG_NET_POLL_CONTROLLER */ 3668 + 3669 + static int bcm43xx_net_open(struct net_device *net_dev) 3670 + { 3671 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3672 + 3673 + return bcm43xx_init_board(bcm); 3674 + } 3675 + 3676 + static int bcm43xx_net_stop(struct net_device *net_dev) 3677 + { 3678 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3679 + 3680 + ieee80211softmac_stop(net_dev); 3681 + bcm43xx_disable_interrupts_sync(bcm, NULL); 3682 + bcm43xx_free_board(bcm); 3683 + 3684 + return 0; 3685 + } 3686 + 3687 + static int bcm43xx_init_private(struct bcm43xx_private *bcm, 3688 + struct net_device *net_dev, 3689 + struct pci_dev *pci_dev) 3690 + { 3691 + int err; 3692 + 3693 + bcm->ieee = netdev_priv(net_dev); 3694 + bcm->softmac = ieee80211_priv(net_dev); 3695 + bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; 3696 + 3697 + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; 3698 + bcm->pci_dev = pci_dev; 3699 + bcm->net_dev = net_dev; 3700 + bcm->bad_frames_preempt = modparam_bad_frames_preempt; 3701 + spin_lock_init(&bcm->_lock); 3702 + tasklet_init(&bcm->isr_tasklet, 3703 + (void (*)(unsigned long))bcm43xx_interrupt_tasklet, 3704 + (unsigned long)bcm); 3705 + tasklet_disable_nosync(&bcm->isr_tasklet); 3706 + if (modparam_pio) { 3707 + bcm->__using_pio = 1; 3708 + } else { 3709 + err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK); 3710 + err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK); 3711 + if (err) { 3712 + #ifdef CONFIG_BCM43XX_PIO 3713 + printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); 3714 + bcm->__using_pio = 1; 3715 + #else 3716 + printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " 3717 + "Recompile the driver with PIO support, please.\n"); 3718 + return -ENODEV; 3719 + #endif /* CONFIG_BCM43XX_PIO */ 3720 + } 3721 + } 3722 + bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; 3723 + 3724 + /* default to sw encryption for now */ 3725 + bcm->ieee->host_build_iv = 0; 3726 + bcm->ieee->host_encrypt = 1; 3727 + bcm->ieee->host_decrypt = 1; 3728 + 3729 + bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE; 3730 + bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); 3731 + bcm->ieee->set_security = bcm43xx_ieee80211_set_security; 3732 + bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; 3733 + 3734 + return 0; 3735 + } 3736 + 3737 + static int __devinit bcm43xx_init_one(struct pci_dev *pdev, 3738 + const struct pci_device_id *ent) 3739 + { 3740 + struct net_device *net_dev; 3741 + struct bcm43xx_private *bcm; 3742 + int err; 3743 + 3744 + #ifdef CONFIG_BCM947XX 3745 + if ((pdev->bus->number == 0) && (pdev->device != 0x0800)) 3746 + return -ENODEV; 3747 + #endif 3748 + 3749 + #ifdef DEBUG_SINGLE_DEVICE_ONLY 3750 + if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY)) 3751 + return -ENODEV; 3752 + #endif 3753 + 3754 + net_dev = alloc_ieee80211softmac(sizeof(*bcm)); 3755 + if (!net_dev) { 3756 + printk(KERN_ERR PFX 3757 + "could not allocate ieee80211 device %s\n", 3758 + pci_name(pdev)); 3759 + err = -ENOMEM; 3760 + goto out; 3761 + } 3762 + /* initialize the net_device struct */ 3763 + SET_MODULE_OWNER(net_dev); 3764 + SET_NETDEV_DEV(net_dev, &pdev->dev); 3765 + 3766 + net_dev->open = bcm43xx_net_open; 3767 + net_dev->stop = bcm43xx_net_stop; 3768 + net_dev->get_stats = bcm43xx_net_get_stats; 3769 + net_dev->tx_timeout = bcm43xx_net_tx_timeout; 3770 + #ifdef CONFIG_NET_POLL_CONTROLLER 3771 + net_dev->poll_controller = bcm43xx_net_poll_controller; 3772 + #endif 3773 + net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; 3774 + net_dev->irq = pdev->irq; 3775 + SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops); 3776 + 3777 + /* initialize the bcm43xx_private struct */ 3778 + bcm = bcm43xx_priv(net_dev); 3779 + memset(bcm, 0, sizeof(*bcm)); 3780 + err = bcm43xx_init_private(bcm, net_dev, pdev); 3781 + if (err) 3782 + goto err_free_netdev; 3783 + 3784 + pci_set_drvdata(pdev, net_dev); 3785 + 3786 + err = bcm43xx_attach_board(bcm); 3787 + if (err) 3788 + goto err_free_netdev; 3789 + 3790 + err = register_netdev(net_dev); 3791 + if (err) { 3792 + printk(KERN_ERR PFX "Cannot register net device, " 3793 + "aborting.\n"); 3794 + err = -ENOMEM; 3795 + goto err_detach_board; 3796 + } 3797 + 3798 + bcm43xx_debugfs_add_device(bcm); 3799 + 3800 + assert(err == 0); 3801 + out: 3802 + return err; 3803 + 3804 + err_detach_board: 3805 + bcm43xx_detach_board(bcm); 3806 + err_free_netdev: 3807 + free_ieee80211softmac(net_dev); 3808 + goto out; 3809 + } 3810 + 3811 + static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) 3812 + { 3813 + struct net_device *net_dev = pci_get_drvdata(pdev); 3814 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3815 + 3816 + bcm43xx_debugfs_remove_device(bcm); 3817 + unregister_netdev(net_dev); 3818 + bcm43xx_detach_board(bcm); 3819 + assert(bcm->ucode == NULL); 3820 + free_ieee80211softmac(net_dev); 3821 + } 3822 + 3823 + /* Hard-reset the chip. Do not call this directly. 3824 + * Use bcm43xx_controller_restart() 3825 + */ 3826 + static void bcm43xx_chip_reset(void *_bcm) 3827 + { 3828 + struct bcm43xx_private *bcm = _bcm; 3829 + struct net_device *net_dev = bcm->net_dev; 3830 + struct pci_dev *pci_dev = bcm->pci_dev; 3831 + int err; 3832 + int was_initialized = bcm->initialized; 3833 + 3834 + netif_stop_queue(bcm->net_dev); 3835 + tasklet_disable(&bcm->isr_tasklet); 3836 + 3837 + bcm->firmware_norelease = 1; 3838 + if (was_initialized) 3839 + bcm43xx_free_board(bcm); 3840 + bcm->firmware_norelease = 0; 3841 + bcm43xx_detach_board(bcm); 3842 + err = bcm43xx_init_private(bcm, net_dev, pci_dev); 3843 + if (err) 3844 + goto failure; 3845 + err = bcm43xx_attach_board(bcm); 3846 + if (err) 3847 + goto failure; 3848 + if (was_initialized) { 3849 + err = bcm43xx_init_board(bcm); 3850 + if (err) 3851 + goto failure; 3852 + } 3853 + netif_wake_queue(bcm->net_dev); 3854 + printk(KERN_INFO PFX "Controller restarted\n"); 3855 + 3856 + return; 3857 + failure: 3858 + printk(KERN_ERR PFX "Controller restart failed\n"); 3859 + } 3860 + 3861 + /* Hard-reset the chip. 3862 + * This can be called from interrupt or process context. 3863 + * Make sure to _not_ re-enable device interrupts after this has been called. 3864 + */ 3865 + void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) 3866 + { 3867 + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 3868 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ 3869 + printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); 3870 + INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); 3871 + schedule_work(&bcm->restart_work); 3872 + } 3873 + 3874 + #ifdef CONFIG_PM 3875 + 3876 + static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) 3877 + { 3878 + struct net_device *net_dev = pci_get_drvdata(pdev); 3879 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3880 + unsigned long flags; 3881 + int try_to_shutdown = 0, err; 3882 + 3883 + dprintk(KERN_INFO PFX "Suspending...\n"); 3884 + 3885 + bcm43xx_lock(bcm, flags); 3886 + bcm->was_initialized = bcm->initialized; 3887 + if (bcm->initialized) 3888 + try_to_shutdown = 1; 3889 + bcm43xx_unlock(bcm, flags); 3890 + 3891 + netif_device_detach(net_dev); 3892 + if (try_to_shutdown) { 3893 + ieee80211softmac_stop(net_dev); 3894 + err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); 3895 + if (unlikely(err)) { 3896 + dprintk(KERN_ERR PFX "Suspend failed.\n"); 3897 + return -EAGAIN; 3898 + } 3899 + bcm->firmware_norelease = 1; 3900 + bcm43xx_free_board(bcm); 3901 + bcm->firmware_norelease = 0; 3902 + } 3903 + bcm43xx_chipset_detach(bcm); 3904 + 3905 + pci_save_state(pdev); 3906 + pci_disable_device(pdev); 3907 + pci_set_power_state(pdev, pci_choose_state(pdev, state)); 3908 + 3909 + dprintk(KERN_INFO PFX "Device suspended.\n"); 3910 + 3911 + return 0; 3912 + } 3913 + 3914 + static int bcm43xx_resume(struct pci_dev *pdev) 3915 + { 3916 + struct net_device *net_dev = pci_get_drvdata(pdev); 3917 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 3918 + int err = 0; 3919 + 3920 + dprintk(KERN_INFO PFX "Resuming...\n"); 3921 + 3922 + pci_set_power_state(pdev, 0); 3923 + pci_enable_device(pdev); 3924 + pci_restore_state(pdev); 3925 + 3926 + bcm43xx_chipset_attach(bcm); 3927 + if (bcm->was_initialized) { 3928 + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; 3929 + err = bcm43xx_init_board(bcm); 3930 + } 3931 + if (err) { 3932 + printk(KERN_ERR PFX "Resume failed!\n"); 3933 + return err; 3934 + } 3935 + 3936 + netif_device_attach(net_dev); 3937 + 3938 + /*FIXME: This should be handled by softmac instead. */ 3939 + schedule_work(&bcm->softmac->associnfo.work); 3940 + 3941 + dprintk(KERN_INFO PFX "Device resumed.\n"); 3942 + 3943 + return 0; 3944 + } 3945 + 3946 + #endif /* CONFIG_PM */ 3947 + 3948 + static struct pci_driver bcm43xx_pci_driver = { 3949 + .name = KBUILD_MODNAME, 3950 + .id_table = bcm43xx_pci_tbl, 3951 + .probe = bcm43xx_init_one, 3952 + .remove = __devexit_p(bcm43xx_remove_one), 3953 + #ifdef CONFIG_PM 3954 + .suspend = bcm43xx_suspend, 3955 + .resume = bcm43xx_resume, 3956 + #endif /* CONFIG_PM */ 3957 + }; 3958 + 3959 + static int __init bcm43xx_init(void) 3960 + { 3961 + printk(KERN_INFO KBUILD_MODNAME " driver\n"); 3962 + bcm43xx_debugfs_init(); 3963 + return pci_register_driver(&bcm43xx_pci_driver); 3964 + } 3965 + 3966 + static void __exit bcm43xx_exit(void) 3967 + { 3968 + pci_unregister_driver(&bcm43xx_pci_driver); 3969 + bcm43xx_debugfs_exit(); 3970 + } 3971 + 3972 + module_init(bcm43xx_init) 3973 + module_exit(bcm43xx_exit)
+168
drivers/net/wireless/bcm43xx/bcm43xx_main.h
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #ifndef BCM43xx_MAIN_H_ 32 + #define BCM43xx_MAIN_H_ 33 + 34 + #include "bcm43xx.h" 35 + 36 + #ifdef CONFIG_BCM947XX 37 + #define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0) 38 + 39 + static inline void e_aton(char *str, char *dest) 40 + { 41 + int i = 0; 42 + u16 *d = (u16 *) dest; 43 + 44 + for (;;) { 45 + dest[i++] = (char) simple_strtoul(str, NULL, 16); 46 + str += 2; 47 + if (!*str++ || i == 6) 48 + break; 49 + } 50 + for (i = 0; i < 3; i++) 51 + d[i] = cpu_to_be16(d[i]); 52 + } 53 + #endif 54 + 55 + #define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] 56 + #define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) 57 + /* Magic helper macro to pad structures. Ignore those above. It's magic. */ 58 + #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) 59 + 60 + 61 + /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ 62 + static inline 63 + u8 bcm43xx_freq_to_channel_a(int freq) 64 + { 65 + return ((freq - 5000) / 5); 66 + } 67 + static inline 68 + u8 bcm43xx_freq_to_channel_bg(int freq) 69 + { 70 + u8 channel; 71 + 72 + if (freq == 2484) 73 + channel = 14; 74 + else 75 + channel = (freq - 2407) / 5; 76 + 77 + return channel; 78 + } 79 + static inline 80 + u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, 81 + int freq) 82 + { 83 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) 84 + return bcm43xx_freq_to_channel_a(freq); 85 + return bcm43xx_freq_to_channel_bg(freq); 86 + } 87 + 88 + /* Lightweight function to convert a channel number to a frequency (in Mhz). */ 89 + static inline 90 + int bcm43xx_channel_to_freq_a(u8 channel) 91 + { 92 + return (5000 + (5 * channel)); 93 + } 94 + static inline 95 + int bcm43xx_channel_to_freq_bg(u8 channel) 96 + { 97 + int freq; 98 + 99 + if (channel == 14) 100 + freq = 2484; 101 + else 102 + freq = 2407 + (5 * channel); 103 + 104 + return freq; 105 + } 106 + static inline 107 + int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, 108 + u8 channel) 109 + { 110 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) 111 + return bcm43xx_channel_to_freq_a(channel); 112 + return bcm43xx_channel_to_freq_bg(channel); 113 + } 114 + 115 + /* Lightweight function to check if a channel number is valid. 116 + * Note that this does _NOT_ check for geographical restrictions! 117 + */ 118 + static inline 119 + int bcm43xx_is_valid_channel_a(u8 channel) 120 + { 121 + return (channel <= 200); 122 + } 123 + static inline 124 + int bcm43xx_is_valid_channel_bg(u8 channel) 125 + { 126 + return (channel >= 1 && channel <= 14); 127 + } 128 + static inline 129 + int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, 130 + u8 channel) 131 + { 132 + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) 133 + return bcm43xx_is_valid_channel_a(channel); 134 + return bcm43xx_is_valid_channel_bg(channel); 135 + } 136 + 137 + void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); 138 + void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); 139 + 140 + void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, 141 + int iw_mode); 142 + 143 + u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, 144 + u16 routing, u16 offset); 145 + u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, 146 + u16 routing, u16 offset); 147 + void bcm43xx_shm_write32(struct bcm43xx_private *bcm, 148 + u16 routing, u16 offset, 149 + u32 value); 150 + void bcm43xx_shm_write16(struct bcm43xx_private *bcm, 151 + u16 routing, u16 offset, 152 + u16 value); 153 + 154 + void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm); 155 + 156 + int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); 157 + 158 + void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); 159 + 160 + void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); 161 + void bcm43xx_mac_enable(struct bcm43xx_private *bcm); 162 + 163 + void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); 164 + 165 + int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); 166 + int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom); 167 + 168 + #endif /* BCM43xx_MAIN_H_ */
+2345
drivers/net/wireless/bcm43xx/bcm43xx_phy.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #include <linux/delay.h> 32 + #include <linux/pci.h> 33 + #include <linux/types.h> 34 + 35 + #include "bcm43xx.h" 36 + #include "bcm43xx_phy.h" 37 + #include "bcm43xx_main.h" 38 + #include "bcm43xx_radio.h" 39 + #include "bcm43xx_ilt.h" 40 + #include "bcm43xx_power.h" 41 + 42 + 43 + static const s8 bcm43xx_tssi2dbm_b_table[] = { 44 + 0x4D, 0x4C, 0x4B, 0x4A, 45 + 0x4A, 0x49, 0x48, 0x47, 46 + 0x47, 0x46, 0x45, 0x45, 47 + 0x44, 0x43, 0x42, 0x42, 48 + 0x41, 0x40, 0x3F, 0x3E, 49 + 0x3D, 0x3C, 0x3B, 0x3A, 50 + 0x39, 0x38, 0x37, 0x36, 51 + 0x35, 0x34, 0x32, 0x31, 52 + 0x30, 0x2F, 0x2D, 0x2C, 53 + 0x2B, 0x29, 0x28, 0x26, 54 + 0x25, 0x23, 0x21, 0x1F, 55 + 0x1D, 0x1A, 0x17, 0x14, 56 + 0x10, 0x0C, 0x06, 0x00, 57 + -7, -7, -7, -7, 58 + -7, -7, -7, -7, 59 + -7, -7, -7, -7, 60 + }; 61 + 62 + static const s8 bcm43xx_tssi2dbm_g_table[] = { 63 + 77, 77, 77, 76, 64 + 76, 76, 75, 75, 65 + 74, 74, 73, 73, 66 + 73, 72, 72, 71, 67 + 71, 70, 70, 69, 68 + 68, 68, 67, 67, 69 + 66, 65, 65, 64, 70 + 63, 63, 62, 61, 71 + 60, 59, 58, 57, 72 + 56, 55, 54, 53, 73 + 52, 50, 49, 47, 74 + 45, 43, 40, 37, 75 + 33, 28, 22, 14, 76 + 5, -7, -20, -20, 77 + -20, -20, -20, -20, 78 + -20, -20, -20, -20, 79 + }; 80 + 81 + static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); 82 + 83 + 84 + void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) 85 + { 86 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 87 + 88 + assert(irqs_disabled()); 89 + if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) { 90 + phy->is_locked = 0; 91 + return; 92 + } 93 + if (bcm->current_core->rev < 3) { 94 + bcm43xx_mac_suspend(bcm); 95 + spin_lock(&phy->lock); 96 + } else { 97 + if (bcm->ieee->iw_mode != IW_MODE_MASTER) 98 + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); 99 + } 100 + phy->is_locked = 1; 101 + } 102 + 103 + void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm) 104 + { 105 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 106 + 107 + assert(irqs_disabled()); 108 + if (bcm->current_core->rev < 3) { 109 + if (phy->is_locked) { 110 + spin_unlock(&phy->lock); 111 + bcm43xx_mac_enable(bcm); 112 + } 113 + } else { 114 + if (bcm->ieee->iw_mode != IW_MODE_MASTER) 115 + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); 116 + } 117 + phy->is_locked = 0; 118 + } 119 + 120 + u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset) 121 + { 122 + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); 123 + return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA); 124 + } 125 + 126 + void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) 127 + { 128 + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); 129 + mmiowb(); 130 + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val); 131 + } 132 + 133 + void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) 134 + { 135 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 136 + unsigned long flags; 137 + 138 + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ 139 + if (phy->calibrated) 140 + return; 141 + if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { 142 + /* We do not want to be preempted while calibrating 143 + * the hardware. 144 + */ 145 + local_irq_save(flags); 146 + 147 + bcm43xx_wireless_core_reset(bcm, 0); 148 + bcm43xx_phy_initg(bcm); 149 + bcm43xx_wireless_core_reset(bcm, 1); 150 + 151 + local_irq_restore(flags); 152 + } 153 + phy->calibrated = 1; 154 + } 155 + 156 + /* Connect the PHY 157 + * http://bcm-specs.sipsolutions.net/SetPHY 158 + */ 159 + int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) 160 + { 161 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 162 + u32 flags; 163 + 164 + if (bcm->current_core->rev < 5) 165 + goto out; 166 + 167 + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); 168 + if (connect) { 169 + if (!(flags & 0x00010000)) 170 + return -ENODEV; 171 + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 172 + flags |= (0x800 << 18); 173 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); 174 + } else { 175 + if (!(flags & 0x00020000)) 176 + return -ENODEV; 177 + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 178 + flags &= ~(0x800 << 18); 179 + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); 180 + } 181 + out: 182 + phy->connected = connect; 183 + if (connect) 184 + dprintk(KERN_INFO PFX "PHY connected\n"); 185 + else 186 + dprintk(KERN_INFO PFX "PHY disconnected\n"); 187 + 188 + return 0; 189 + } 190 + 191 + /* intialize B PHY power control 192 + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl 193 + */ 194 + static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) 195 + { 196 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 197 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 198 + u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0; 199 + int must_reset_txpower = 0; 200 + 201 + assert(phy->type != BCM43xx_PHYTYPE_A); 202 + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && 203 + (bcm->board_type == 0x0416)) 204 + return; 205 + 206 + bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF); 207 + bcm43xx_phy_write(bcm, 0x0028, 0x8018); 208 + 209 + if (phy->type == BCM43xx_PHYTYPE_G) { 210 + if (!phy->connected) 211 + return; 212 + bcm43xx_phy_write(bcm, 0x047A, 0xC111); 213 + } 214 + if (phy->savedpctlreg != 0xFFFF) 215 + return; 216 + 217 + if (phy->type == BCM43xx_PHYTYPE_B && 218 + phy->rev >= 2 && 219 + radio->version == 0x2050) { 220 + bcm43xx_radio_write16(bcm, 0x0076, 221 + bcm43xx_radio_read16(bcm, 0x0076) | 0x0084); 222 + } else { 223 + saved_batt = radio->baseband_atten; 224 + saved_ratt = radio->radio_atten; 225 + saved_txctl1 = radio->txctl1; 226 + if ((radio->revision >= 6) && (radio->revision <= 8) 227 + && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) 228 + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0); 229 + else 230 + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0); 231 + must_reset_txpower = 1; 232 + } 233 + bcm43xx_dummy_transmission(bcm); 234 + 235 + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL); 236 + 237 + if (must_reset_txpower) 238 + bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1); 239 + else 240 + bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B); 241 + bcm43xx_radio_clear_tssi(bcm); 242 + } 243 + 244 + static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) 245 + { 246 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 247 + u16 offset = 0x0000; 248 + 249 + if (phy->rev == 1) 250 + offset = 0x4C00; 251 + 252 + bcm43xx_ilt_write(bcm, offset, 0x00FE); 253 + bcm43xx_ilt_write(bcm, offset + 1, 0x000D); 254 + bcm43xx_ilt_write(bcm, offset + 2, 0x0013); 255 + bcm43xx_ilt_write(bcm, offset + 3, 0x0019); 256 + 257 + if (phy->rev == 1) { 258 + bcm43xx_ilt_write(bcm, 0x1800, 0x2710); 259 + bcm43xx_ilt_write(bcm, 0x1801, 0x9B83); 260 + bcm43xx_ilt_write(bcm, 0x1802, 0x9B83); 261 + bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D); 262 + bcm43xx_phy_write(bcm, 0x0455, 0x0004); 263 + } 264 + 265 + bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700); 266 + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F); 267 + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80); 268 + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300); 269 + 270 + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008); 271 + 272 + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008); 273 + bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600); 274 + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700); 275 + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100); 276 + 277 + if (phy->rev == 1) 278 + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007); 279 + 280 + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C); 281 + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200); 282 + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C); 283 + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020); 284 + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200); 285 + bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E); 286 + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00); 287 + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028); 288 + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00); 289 + 290 + if (phy->rev == 1) { 291 + bcm43xx_phy_write(bcm, 0x0430, 0x092B); 292 + bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002); 293 + } else { 294 + bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1); 295 + bcm43xx_phy_write(bcm, 0x041F, 0x287A); 296 + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004); 297 + } 298 + 299 + if (phy->rev > 2) { 300 + bcm43xx_phy_write(bcm, 0x0422, 0x287A); 301 + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); 302 + } 303 + 304 + bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874); 305 + bcm43xx_phy_write(bcm, 0x048E, 0x1C00); 306 + 307 + if (phy->rev == 1) { 308 + bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600); 309 + bcm43xx_phy_write(bcm, 0x048B, 0x005E); 310 + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E); 311 + bcm43xx_phy_write(bcm, 0x048D, 0x0002); 312 + } 313 + 314 + bcm43xx_ilt_write(bcm, offset + 0x0800, 0); 315 + bcm43xx_ilt_write(bcm, offset + 0x0801, 7); 316 + bcm43xx_ilt_write(bcm, offset + 0x0802, 16); 317 + bcm43xx_ilt_write(bcm, offset + 0x0803, 28); 318 + } 319 + 320 + static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) 321 + { 322 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 323 + u16 i; 324 + 325 + assert(phy->type == BCM43xx_PHYTYPE_G); 326 + if (phy->rev == 1) { 327 + bcm43xx_phy_write(bcm, 0x0406, 0x4F19); 328 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 329 + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340); 330 + bcm43xx_phy_write(bcm, 0x042C, 0x005A); 331 + bcm43xx_phy_write(bcm, 0x0427, 0x001A); 332 + 333 + for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++) 334 + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); 335 + for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) 336 + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); 337 + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) 338 + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); 339 + } else { 340 + /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ 341 + bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); 342 + 343 + if (phy->rev == 2) { 344 + bcm43xx_phy_write(bcm, 0x04C0, 0x1861); 345 + bcm43xx_phy_write(bcm, 0x04C1, 0x0271); 346 + } else if (phy->rev > 2) { 347 + bcm43xx_phy_write(bcm, 0x04C0, 0x0098); 348 + bcm43xx_phy_write(bcm, 0x04C1, 0x0070); 349 + bcm43xx_phy_write(bcm, 0x04C9, 0x0080); 350 + } 351 + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800); 352 + 353 + for (i = 0; i < 64; i++) 354 + bcm43xx_ilt_write(bcm, 0x4000 + i, i); 355 + for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++) 356 + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); 357 + } 358 + 359 + if (phy->rev <= 2) 360 + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) 361 + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); 362 + else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) 363 + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) 364 + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); 365 + else 366 + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) 367 + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); 368 + 369 + if (phy->rev == 2) 370 + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) 371 + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); 372 + else if ((phy->rev > 2) && (phy->rev <= 7)) 373 + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) 374 + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); 375 + 376 + if (phy->rev == 1) { 377 + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) 378 + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); 379 + for (i = 0; i < 4; i++) { 380 + bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020); 381 + bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020); 382 + bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020); 383 + bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020); 384 + } 385 + bcm43xx_phy_agcsetup(bcm); 386 + 387 + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && 388 + (bcm->board_type == 0x0416) && 389 + (bcm->board_revision == 0x0017)) 390 + return; 391 + 392 + bcm43xx_ilt_write(bcm, 0x5001, 0x0002); 393 + bcm43xx_ilt_write(bcm, 0x5002, 0x0001); 394 + } else { 395 + for (i = 0; i <= 0x2F; i++) 396 + bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820); 397 + bcm43xx_phy_agcsetup(bcm); 398 + bcm43xx_phy_read(bcm, 0x0400); /* dummy read */ 399 + bcm43xx_phy_write(bcm, 0x0403, 0x1000); 400 + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); 401 + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); 402 + 403 + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && 404 + (bcm->board_type == 0x0416) && 405 + (bcm->board_revision == 0x0017)) 406 + return; 407 + 408 + bcm43xx_ilt_write(bcm, 0x0401, 0x0002); 409 + bcm43xx_ilt_write(bcm, 0x0402, 0x0001); 410 + } 411 + } 412 + 413 + /* Initialize the noisescaletable for APHY */ 414 + static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) 415 + { 416 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 417 + int i; 418 + 419 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400); 420 + for (i = 0; i < 12; i++) { 421 + if (phy->rev == 2) 422 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); 423 + else 424 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); 425 + } 426 + if (phy->rev == 2) 427 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700); 428 + else 429 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300); 430 + for (i = 0; i < 11; i++) { 431 + if (phy->rev == 2) 432 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); 433 + else 434 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); 435 + } 436 + if (phy->rev == 2) 437 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067); 438 + else 439 + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023); 440 + } 441 + 442 + static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) 443 + { 444 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 445 + u16 i; 446 + 447 + assert(phy->type == BCM43xx_PHYTYPE_A); 448 + switch (phy->rev) { 449 + case 2: 450 + bcm43xx_phy_write(bcm, 0x008E, 0x3800); 451 + bcm43xx_phy_write(bcm, 0x0035, 0x03FF); 452 + bcm43xx_phy_write(bcm, 0x0036, 0x0400); 453 + 454 + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); 455 + 456 + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); 457 + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); 458 + bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF); 459 + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); 460 + 461 + bcm43xx_phy_write(bcm, 0x0024, 0x4680); 462 + bcm43xx_phy_write(bcm, 0x0020, 0x0003); 463 + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); 464 + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); 465 + 466 + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); 467 + bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF); 468 + bcm43xx_phy_write(bcm, 0x008E, 0x58C1); 469 + 470 + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); 471 + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); 472 + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); 473 + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); 474 + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); 475 + 476 + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); 477 + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); 478 + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); 479 + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); 480 + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); 481 + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); 482 + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); 483 + 484 + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); 485 + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); 486 + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); 487 + 488 + for (i = 0; i < 16; i++) 489 + bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F); 490 + 491 + bcm43xx_ilt_write(bcm, 0x3003, 0x1044); 492 + bcm43xx_ilt_write(bcm, 0x3004, 0x7201); 493 + bcm43xx_ilt_write(bcm, 0x3006, 0x0040); 494 + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); 495 + 496 + for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++) 497 + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); 498 + for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) 499 + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); 500 + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) 501 + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); 502 + bcm43xx_phy_init_noisescaletbl(bcm); 503 + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) 504 + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); 505 + break; 506 + case 3: 507 + for (i = 0; i < 64; i++) 508 + bcm43xx_ilt_write(bcm, 0x4000 + i, i); 509 + 510 + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); 511 + 512 + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); 513 + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); 514 + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); 515 + 516 + bcm43xx_phy_write(bcm, 0x0024, 0x4680); 517 + bcm43xx_phy_write(bcm, 0x0020, 0x0003); 518 + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); 519 + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); 520 + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); 521 + 522 + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); 523 + for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++) 524 + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); 525 + bcm43xx_phy_init_noisescaletbl(bcm); 526 + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) 527 + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); 528 + 529 + bcm43xx_phy_write(bcm, 0x0003, 0x1808); 530 + 531 + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); 532 + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); 533 + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); 534 + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); 535 + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); 536 + 537 + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); 538 + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); 539 + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); 540 + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); 541 + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); 542 + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); 543 + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); 544 + 545 + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); 546 + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); 547 + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); 548 + 549 + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); 550 + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); 551 + break; 552 + default: 553 + assert(0); 554 + } 555 + } 556 + 557 + /* Initialize APHY. This is also called for the GPHY in some cases. */ 558 + static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) 559 + { 560 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 561 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 562 + u16 tval; 563 + 564 + if (phy->type == BCM43xx_PHYTYPE_A) { 565 + bcm43xx_phy_setupa(bcm); 566 + } else { 567 + bcm43xx_phy_setupg(bcm); 568 + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) 569 + bcm43xx_phy_write(bcm, 0x046E, 0x03CF); 570 + return; 571 + } 572 + 573 + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, 574 + (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340); 575 + bcm43xx_phy_write(bcm, 0x0034, 0x0001); 576 + 577 + TODO();//TODO: RSSI AGC 578 + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, 579 + bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14)); 580 + bcm43xx_radio_init2060(bcm); 581 + 582 + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) 583 + && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) { 584 + if (radio->lofcal == 0xFFFF) { 585 + TODO();//TODO: LOF Cal 586 + bcm43xx_radio_set_tx_iq(bcm); 587 + } else 588 + bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal); 589 + } 590 + 591 + bcm43xx_phy_write(bcm, 0x007A, 0xF111); 592 + 593 + if (phy->savedpctlreg == 0xFFFF) { 594 + bcm43xx_radio_write16(bcm, 0x0019, 0x0000); 595 + bcm43xx_radio_write16(bcm, 0x0017, 0x0020); 596 + 597 + tval = bcm43xx_ilt_read(bcm, 0x3001); 598 + if (phy->rev == 1) { 599 + bcm43xx_ilt_write(bcm, 0x3001, 600 + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87) 601 + | 0x0058); 602 + } else { 603 + bcm43xx_ilt_write(bcm, 0x3001, 604 + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3) 605 + | 0x002C); 606 + } 607 + bcm43xx_dummy_transmission(bcm); 608 + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL); 609 + bcm43xx_ilt_write(bcm, 0x3001, tval); 610 + 611 + bcm43xx_radio_set_txpower_a(bcm, 0x0018); 612 + } 613 + bcm43xx_radio_clear_tssi(bcm); 614 + } 615 + 616 + static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) 617 + { 618 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 619 + u16 offset, val; 620 + 621 + bcm43xx_write16(bcm, 0x03EC, 0x3F22); 622 + bcm43xx_phy_write(bcm, 0x0020, 0x301C); 623 + bcm43xx_phy_write(bcm, 0x0026, 0x0000); 624 + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); 625 + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); 626 + val = 0x3C3D; 627 + for (offset = 0x0089; offset < 0x00A7; offset++) { 628 + bcm43xx_phy_write(bcm, offset, val); 629 + val -= 0x0202; 630 + } 631 + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); 632 + if (radio->channel == 0xFF) 633 + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); 634 + else 635 + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); 636 + if (radio->version != 0x2050) { 637 + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); 638 + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); 639 + } 640 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 641 + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); 642 + if (radio->version == 0x2050) { 643 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 644 + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); 645 + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); 646 + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); 647 + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); 648 + bcm43xx_phy_write(bcm, 0x0038, 0x0677); 649 + bcm43xx_radio_init2050(bcm); 650 + } 651 + bcm43xx_phy_write(bcm, 0x0014, 0x0080); 652 + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); 653 + bcm43xx_phy_write(bcm, 0x0032, 0x00CC); 654 + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); 655 + bcm43xx_phy_lo_b_measure(bcm); 656 + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); 657 + if (radio->version != 0x2050) 658 + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); 659 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000); 660 + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); 661 + if (radio->version != 0x2050) 662 + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); 663 + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); 664 + bcm43xx_phy_init_pctl(bcm); 665 + } 666 + 667 + static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) 668 + { 669 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 670 + u16 offset, val; 671 + 672 + bcm43xx_write16(bcm, 0x03EC, 0x3F22); 673 + bcm43xx_phy_write(bcm, 0x0020, 0x301C); 674 + bcm43xx_phy_write(bcm, 0x0026, 0x0000); 675 + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); 676 + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); 677 + val = 0x3C3D; 678 + for (offset = 0x0089; offset < 0x00A7; offset++) { 679 + bcm43xx_phy_write(bcm, offset, val); 680 + val -= 0x0202; 681 + } 682 + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); 683 + if (radio->channel == 0xFF) 684 + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); 685 + else 686 + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); 687 + if (radio->version != 0x2050) { 688 + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); 689 + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); 690 + } 691 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 692 + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); 693 + if (radio->version == 0x2050) { 694 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 695 + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); 696 + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); 697 + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); 698 + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); 699 + bcm43xx_phy_write(bcm, 0x0038, 0x0677); 700 + bcm43xx_radio_init2050(bcm); 701 + } 702 + bcm43xx_phy_write(bcm, 0x0014, 0x0080); 703 + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); 704 + if (radio->version == 0x2050) 705 + bcm43xx_phy_write(bcm, 0x0032, 0x00E0); 706 + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); 707 + 708 + bcm43xx_phy_lo_b_measure(bcm); 709 + 710 + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); 711 + if (radio->version == 0x2050) 712 + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); 713 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100); 714 + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); 715 + if (radio->version == 0x2050) 716 + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); 717 + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); 718 + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { 719 + bcm43xx_calc_nrssi_slope(bcm); 720 + bcm43xx_calc_nrssi_threshold(bcm); 721 + } 722 + bcm43xx_phy_init_pctl(bcm); 723 + } 724 + 725 + static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) 726 + { 727 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 728 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 729 + u16 offset; 730 + 731 + if (phy->version == 1 && 732 + radio->version == 0x2050) { 733 + bcm43xx_radio_write16(bcm, 0x007A, 734 + bcm43xx_radio_read16(bcm, 0x007A) 735 + | 0x0050); 736 + } 737 + if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) && 738 + (bcm->board_type != 0x0416)) { 739 + for (offset = 0x00A8 ; offset < 0x00C7; offset++) { 740 + bcm43xx_phy_write(bcm, offset, 741 + (bcm43xx_phy_read(bcm, offset) + 0x2020) 742 + & 0x3F3F); 743 + } 744 + } 745 + bcm43xx_phy_write(bcm, 0x0035, 746 + (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF) 747 + | 0x0700); 748 + if (radio->version == 0x2050) 749 + bcm43xx_phy_write(bcm, 0x0038, 0x0667); 750 + 751 + if (phy->connected) { 752 + if (radio->version == 0x2050) { 753 + bcm43xx_radio_write16(bcm, 0x007A, 754 + bcm43xx_radio_read16(bcm, 0x007A) 755 + | 0x0020); 756 + bcm43xx_radio_write16(bcm, 0x0051, 757 + bcm43xx_radio_read16(bcm, 0x0051) 758 + | 0x0004); 759 + } 760 + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000); 761 + 762 + bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100); 763 + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000); 764 + 765 + bcm43xx_phy_write(bcm, 0x001C, 0x186A); 766 + 767 + bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900); 768 + bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064); 769 + bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A); 770 + } 771 + 772 + if (bcm->bad_frames_preempt) { 773 + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, 774 + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11)); 775 + } 776 + 777 + if (phy->version == 1 && radio->version == 0x2050) { 778 + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); 779 + bcm43xx_phy_write(bcm, 0x0021, 0x3763); 780 + bcm43xx_phy_write(bcm, 0x0022, 0x1BC3); 781 + bcm43xx_phy_write(bcm, 0x0023, 0x06F9); 782 + bcm43xx_phy_write(bcm, 0x0024, 0x037E); 783 + } else 784 + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); 785 + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); 786 + bcm43xx_write16(bcm, 0x03EC, 0x3F22); 787 + 788 + if (phy->version == 1 && radio->version == 0x2050) 789 + bcm43xx_phy_write(bcm, 0x0020, 0x3E1C); 790 + else 791 + bcm43xx_phy_write(bcm, 0x0020, 0x301C); 792 + 793 + if (phy->version == 0) 794 + bcm43xx_write16(bcm, 0x03E4, 0x3000); 795 + 796 + /* Force to channel 7, even if not supported. */ 797 + bcm43xx_radio_selectchannel(bcm, 7, 0); 798 + 799 + if (radio->version != 0x2050) { 800 + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); 801 + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); 802 + } 803 + 804 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 805 + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); 806 + 807 + if (radio->version == 0x2050) { 808 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 809 + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); 810 + } 811 + 812 + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); 813 + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); 814 + 815 + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007); 816 + 817 + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); 818 + 819 + bcm43xx_phy_write(bcm, 0x0014, 0x0080); 820 + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); 821 + bcm43xx_phy_write(bcm, 0x88A3, 0x002A); 822 + 823 + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); 824 + 825 + if (radio->version == 0x2050) 826 + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); 827 + 828 + bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004); 829 + } 830 + 831 + static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) 832 + { 833 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 834 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 835 + u16 offset, val; 836 + 837 + bcm43xx_phy_write(bcm, 0x003E, 0x817A); 838 + bcm43xx_radio_write16(bcm, 0x007A, 839 + (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058)); 840 + if ((radio->manufact == 0x17F) && 841 + (radio->version == 0x2050) && 842 + (radio->revision == 3 || 843 + radio->revision == 4 || 844 + radio->revision == 5)) { 845 + bcm43xx_radio_write16(bcm, 0x0051, 0x001F); 846 + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); 847 + bcm43xx_radio_write16(bcm, 0x0053, 0x005B); 848 + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); 849 + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); 850 + bcm43xx_radio_write16(bcm, 0x005B, 0x0088); 851 + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); 852 + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); 853 + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); 854 + } 855 + if ((radio->manufact == 0x17F) && 856 + (radio->version == 0x2050) && 857 + (radio->revision == 6)) { 858 + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); 859 + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); 860 + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); 861 + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); 862 + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); 863 + bcm43xx_radio_write16(bcm, 0x005B, 0x008B); 864 + bcm43xx_radio_write16(bcm, 0x005C, 0x00B5); 865 + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); 866 + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); 867 + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); 868 + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); 869 + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); 870 + } 871 + if ((radio->manufact == 0x17F) && 872 + (radio->version == 0x2050) && 873 + (radio->revision == 7)) { 874 + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); 875 + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); 876 + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); 877 + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); 878 + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); 879 + bcm43xx_radio_write16(bcm, 0x005B, 0x00A8); 880 + bcm43xx_radio_write16(bcm, 0x005C, 0x0075); 881 + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); 882 + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); 883 + bcm43xx_radio_write16(bcm, 0x007D, 0x00E8); 884 + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); 885 + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); 886 + bcm43xx_radio_write16(bcm, 0x007B, 0x0000); 887 + } 888 + if ((radio->manufact == 0x17F) && 889 + (radio->version == 0x2050) && 890 + (radio->revision == 8)) { 891 + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); 892 + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); 893 + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); 894 + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); 895 + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); 896 + bcm43xx_radio_write16(bcm, 0x005B, 0x006B); 897 + bcm43xx_radio_write16(bcm, 0x005C, 0x000F); 898 + if (bcm->sprom.boardflags & 0x8000) { 899 + bcm43xx_radio_write16(bcm, 0x005D, 0x00FA); 900 + bcm43xx_radio_write16(bcm, 0x005E, 0x00D8); 901 + } else { 902 + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); 903 + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); 904 + } 905 + bcm43xx_radio_write16(bcm, 0x0073, 0x0003); 906 + bcm43xx_radio_write16(bcm, 0x007D, 0x00A8); 907 + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); 908 + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); 909 + } 910 + val = 0x1E1F; 911 + for (offset = 0x0088; offset < 0x0098; offset++) { 912 + bcm43xx_phy_write(bcm, offset, val); 913 + val -= 0x0202; 914 + } 915 + val = 0x3E3F; 916 + for (offset = 0x0098; offset < 0x00A8; offset++) { 917 + bcm43xx_phy_write(bcm, offset, val); 918 + val -= 0x0202; 919 + } 920 + val = 0x2120; 921 + for (offset = 0x00A8; offset < 0x00C8; offset++) { 922 + bcm43xx_phy_write(bcm, offset, (val & 0x3F3F)); 923 + val += 0x0202; 924 + } 925 + if (phy->type == BCM43xx_PHYTYPE_G) { 926 + bcm43xx_radio_write16(bcm, 0x007A, 927 + bcm43xx_radio_read16(bcm, 0x007A) | 0x0020); 928 + bcm43xx_radio_write16(bcm, 0x0051, 929 + bcm43xx_radio_read16(bcm, 0x0051) | 0x0004); 930 + bcm43xx_phy_write(bcm, 0x0802, 931 + bcm43xx_phy_read(bcm, 0x0802) | 0x0100); 932 + bcm43xx_phy_write(bcm, 0x042B, 933 + bcm43xx_phy_read(bcm, 0x042B) | 0x2000); 934 + } 935 + 936 + /* Force to channel 7, even if not supported. */ 937 + bcm43xx_radio_selectchannel(bcm, 7, 0); 938 + 939 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 940 + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); 941 + udelay(40); 942 + bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002)); 943 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 944 + if (radio->manufact == 0x17F && 945 + radio->version == 0x2050 && 946 + radio->revision <= 2) { 947 + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); 948 + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); 949 + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); 950 + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); 951 + } 952 + bcm43xx_radio_write16(bcm, 0x007A, 953 + (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007); 954 + 955 + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); 956 + 957 + bcm43xx_phy_write(bcm, 0x0014, 0x0200); 958 + if (radio->version == 0x2050){ 959 + if (radio->revision == 3 || 960 + radio->revision == 4 || 961 + radio->revision == 5) 962 + bcm43xx_phy_write(bcm, 0x002A, 0x8AC0); 963 + else 964 + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); 965 + } 966 + bcm43xx_phy_write(bcm, 0x0038, 0x0668); 967 + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); 968 + if (radio->version == 0x2050) { 969 + if (radio->revision == 3 || 970 + radio->revision == 4 || 971 + radio->revision == 5) 972 + bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003); 973 + else if (radio->revision <= 2) 974 + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); 975 + } 976 + 977 + if (phy->rev == 4) 978 + bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004); 979 + else 980 + bcm43xx_write16(bcm, 0x03E4, 0x0009); 981 + if (phy->type == BCM43xx_PHYTYPE_B) { 982 + bcm43xx_write16(bcm, 0x03E6, 0x8140); 983 + bcm43xx_phy_write(bcm, 0x0016, 0x0410); 984 + bcm43xx_phy_write(bcm, 0x0017, 0x0820); 985 + bcm43xx_phy_write(bcm, 0x0062, 0x0007); 986 + (void) bcm43xx_radio_calibrationvalue(bcm); 987 + bcm43xx_phy_lo_b_measure(bcm); 988 + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { 989 + bcm43xx_calc_nrssi_slope(bcm); 990 + bcm43xx_calc_nrssi_threshold(bcm); 991 + } 992 + bcm43xx_phy_init_pctl(bcm); 993 + } else 994 + bcm43xx_write16(bcm, 0x03E6, 0x0); 995 + } 996 + 997 + static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm) 998 + { 999 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1000 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1001 + u16 backup_phy[15]; 1002 + u16 backup_radio[3]; 1003 + u16 backup_bband; 1004 + u16 i; 1005 + u16 loop1_cnt, loop1_done, loop1_omitted; 1006 + u16 loop2_done; 1007 + 1008 + backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429); 1009 + backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001); 1010 + backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811); 1011 + backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812); 1012 + backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814); 1013 + backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815); 1014 + backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A); 1015 + backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059); 1016 + backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058); 1017 + backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A); 1018 + backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003); 1019 + backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F); 1020 + backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810); 1021 + backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B); 1022 + backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015); 1023 + bcm43xx_phy_read(bcm, 0x002D); /* dummy read */ 1024 + backup_bband = radio->baseband_atten; 1025 + backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052); 1026 + backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043); 1027 + backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A); 1028 + 1029 + bcm43xx_phy_write(bcm, 0x0429, 1030 + bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF); 1031 + bcm43xx_phy_write(bcm, 0x0001, 1032 + bcm43xx_phy_read(bcm, 0x0001) & 0x8000); 1033 + bcm43xx_phy_write(bcm, 0x0811, 1034 + bcm43xx_phy_read(bcm, 0x0811) | 0x0002); 1035 + bcm43xx_phy_write(bcm, 0x0812, 1036 + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD); 1037 + bcm43xx_phy_write(bcm, 0x0811, 1038 + bcm43xx_phy_read(bcm, 0x0811) | 0x0001); 1039 + bcm43xx_phy_write(bcm, 0x0812, 1040 + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE); 1041 + bcm43xx_phy_write(bcm, 0x0814, 1042 + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); 1043 + bcm43xx_phy_write(bcm, 0x0815, 1044 + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); 1045 + bcm43xx_phy_write(bcm, 0x0814, 1046 + bcm43xx_phy_read(bcm, 0x0814) | 0x0002); 1047 + bcm43xx_phy_write(bcm, 0x0815, 1048 + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD); 1049 + bcm43xx_phy_write(bcm, 0x0811, 1050 + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); 1051 + bcm43xx_phy_write(bcm, 0x0812, 1052 + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); 1053 + 1054 + bcm43xx_phy_write(bcm, 0x0811, 1055 + (bcm43xx_phy_read(bcm, 0x0811) 1056 + & 0xFFCF) | 0x0030); 1057 + bcm43xx_phy_write(bcm, 0x0812, 1058 + (bcm43xx_phy_read(bcm, 0x0812) 1059 + & 0xFFCF) | 0x0010); 1060 + 1061 + bcm43xx_phy_write(bcm, 0x005A, 0x0780); 1062 + bcm43xx_phy_write(bcm, 0x0059, 0xC810); 1063 + bcm43xx_phy_write(bcm, 0x0058, 0x000D); 1064 + if (phy->version == 0) { 1065 + bcm43xx_phy_write(bcm, 0x0003, 0x0122); 1066 + } else { 1067 + bcm43xx_phy_write(bcm, 0x000A, 1068 + bcm43xx_phy_read(bcm, 0x000A) 1069 + | 0x2000); 1070 + } 1071 + bcm43xx_phy_write(bcm, 0x0814, 1072 + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); 1073 + bcm43xx_phy_write(bcm, 0x0815, 1074 + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); 1075 + bcm43xx_phy_write(bcm, 0x0003, 1076 + (bcm43xx_phy_read(bcm, 0x0003) 1077 + & 0xFF9F) | 0x0040); 1078 + if (radio->version == 0x2050 && radio->revision == 2) { 1079 + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); 1080 + bcm43xx_radio_write16(bcm, 0x0043, 1081 + (bcm43xx_radio_read16(bcm, 0x0043) 1082 + & 0xFFF0) | 0x0009); 1083 + loop1_cnt = 9; 1084 + } else if (radio->revision == 8) { 1085 + bcm43xx_radio_write16(bcm, 0x0043, 0x000F); 1086 + loop1_cnt = 15; 1087 + } else 1088 + loop1_cnt = 0; 1089 + 1090 + bcm43xx_phy_set_baseband_attenuation(bcm, 11); 1091 + 1092 + if (phy->rev >= 3) 1093 + bcm43xx_phy_write(bcm, 0x080F, 0xC020); 1094 + else 1095 + bcm43xx_phy_write(bcm, 0x080F, 0x8020); 1096 + bcm43xx_phy_write(bcm, 0x0810, 0x0000); 1097 + 1098 + bcm43xx_phy_write(bcm, 0x002B, 1099 + (bcm43xx_phy_read(bcm, 0x002B) 1100 + & 0xFFC0) | 0x0001); 1101 + bcm43xx_phy_write(bcm, 0x002B, 1102 + (bcm43xx_phy_read(bcm, 0x002B) 1103 + & 0xC0FF) | 0x0800); 1104 + bcm43xx_phy_write(bcm, 0x0811, 1105 + bcm43xx_phy_read(bcm, 0x0811) | 0x0100); 1106 + bcm43xx_phy_write(bcm, 0x0812, 1107 + bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF); 1108 + if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) { 1109 + if (phy->rev >= 7) { 1110 + bcm43xx_phy_write(bcm, 0x0811, 1111 + bcm43xx_phy_read(bcm, 0x0811) 1112 + | 0x0800); 1113 + bcm43xx_phy_write(bcm, 0x0812, 1114 + bcm43xx_phy_read(bcm, 0x0812) 1115 + | 0x8000); 1116 + } 1117 + } 1118 + bcm43xx_radio_write16(bcm, 0x007A, 1119 + bcm43xx_radio_read16(bcm, 0x007A) 1120 + & 0x00F7); 1121 + 1122 + for (i = 0; i < loop1_cnt; i++) { 1123 + bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt); 1124 + bcm43xx_phy_write(bcm, 0x0812, 1125 + (bcm43xx_phy_read(bcm, 0x0812) 1126 + & 0xF0FF) | (i << 8)); 1127 + bcm43xx_phy_write(bcm, 0x0015, 1128 + (bcm43xx_phy_read(bcm, 0x0015) 1129 + & 0x0FFF) | 0xA000); 1130 + bcm43xx_phy_write(bcm, 0x0015, 1131 + (bcm43xx_phy_read(bcm, 0x0015) 1132 + & 0x0FFF) | 0xF000); 1133 + udelay(20); 1134 + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) 1135 + break; 1136 + } 1137 + loop1_done = i; 1138 + loop1_omitted = loop1_cnt - loop1_done; 1139 + 1140 + loop2_done = 0; 1141 + if (loop1_done >= 8) { 1142 + bcm43xx_phy_write(bcm, 0x0812, 1143 + bcm43xx_phy_read(bcm, 0x0812) 1144 + | 0x0030); 1145 + for (i = loop1_done - 8; i < 16; i++) { 1146 + bcm43xx_phy_write(bcm, 0x0812, 1147 + (bcm43xx_phy_read(bcm, 0x0812) 1148 + & 0xF0FF) | (i << 8)); 1149 + bcm43xx_phy_write(bcm, 0x0015, 1150 + (bcm43xx_phy_read(bcm, 0x0015) 1151 + & 0x0FFF) | 0xA000); 1152 + bcm43xx_phy_write(bcm, 0x0015, 1153 + (bcm43xx_phy_read(bcm, 0x0015) 1154 + & 0x0FFF) | 0xF000); 1155 + udelay(20); 1156 + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) 1157 + break; 1158 + } 1159 + } 1160 + 1161 + bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]); 1162 + bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]); 1163 + bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]); 1164 + bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]); 1165 + bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]); 1166 + bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]); 1167 + bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]); 1168 + bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]); 1169 + bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]); 1170 + bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]); 1171 + bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]); 1172 + 1173 + bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband); 1174 + 1175 + bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]); 1176 + bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]); 1177 + bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]); 1178 + 1179 + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003); 1180 + udelay(10); 1181 + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]); 1182 + bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]); 1183 + bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]); 1184 + bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]); 1185 + 1186 + phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; 1187 + phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; 1188 + } 1189 + 1190 + static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) 1191 + { 1192 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1193 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1194 + u16 tmp; 1195 + 1196 + if (phy->rev == 1) 1197 + bcm43xx_phy_initb5(bcm); 1198 + else if (phy->rev >= 2 && phy->rev <= 7) 1199 + bcm43xx_phy_initb6(bcm); 1200 + if (phy->rev >= 2 || phy->connected) 1201 + bcm43xx_phy_inita(bcm); 1202 + 1203 + if (phy->rev >= 2) { 1204 + bcm43xx_phy_write(bcm, 0x0814, 0x0000); 1205 + bcm43xx_phy_write(bcm, 0x0815, 0x0000); 1206 + if (phy->rev == 2) 1207 + bcm43xx_phy_write(bcm, 0x0811, 0x0000); 1208 + else if (phy->rev >= 3) 1209 + bcm43xx_phy_write(bcm, 0x0811, 0x0400); 1210 + bcm43xx_phy_write(bcm, 0x0015, 0x00C0); 1211 + if (phy->connected) { 1212 + tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; 1213 + if (tmp < 6) { 1214 + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); 1215 + bcm43xx_phy_write(bcm, 0x04C3, 0x8006); 1216 + if (tmp != 3) { 1217 + bcm43xx_phy_write(bcm, 0x04CC, 1218 + (bcm43xx_phy_read(bcm, 0x04CC) 1219 + & 0x00FF) | 0x1F00); 1220 + } 1221 + } 1222 + } 1223 + } 1224 + if (phy->rev < 3 && phy->connected) 1225 + bcm43xx_phy_write(bcm, 0x047E, 0x0078); 1226 + if (phy->rev >= 6 && phy->rev <= 8) { 1227 + bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); 1228 + bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); 1229 + } 1230 + if (phy->rev >= 2 && phy->connected) 1231 + bcm43xx_calc_loopback_gain(bcm); 1232 + if (radio->revision != 8) { 1233 + if (radio->initval == 0xFFFF) 1234 + radio->initval = bcm43xx_radio_init2050(bcm); 1235 + else 1236 + bcm43xx_radio_write16(bcm, 0x0078, radio->initval); 1237 + } 1238 + if (radio->txctl2 == 0xFFFF) { 1239 + bcm43xx_phy_lo_g_measure(bcm); 1240 + } else { 1241 + if (radio->version == 0x2050 && radio->revision == 8) { 1242 + //FIXME 1243 + } else { 1244 + bcm43xx_radio_write16(bcm, 0x0052, 1245 + (bcm43xx_radio_read16(bcm, 0x0052) 1246 + & 0xFFF0) | radio->txctl1); 1247 + } 1248 + if (phy->rev >= 6) { 1249 + /* 1250 + bcm43xx_phy_write(bcm, 0x0036, 1251 + (bcm43xx_phy_read(bcm, 0x0036) 1252 + & 0xF000) | (FIXME << 12)); 1253 + */ 1254 + } 1255 + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) 1256 + bcm43xx_phy_write(bcm, 0x002E, 0x8075); 1257 + else 1258 + bcm43xx_phy_write(bcm, 0x003E, 0x807F); 1259 + if (phy->rev < 2) 1260 + bcm43xx_phy_write(bcm, 0x002F, 0x0101); 1261 + else 1262 + bcm43xx_phy_write(bcm, 0x002F, 0x0202); 1263 + } 1264 + if (phy->connected) { 1265 + bcm43xx_phy_lo_adjust(bcm, 0); 1266 + bcm43xx_phy_write(bcm, 0x080F, 0x8078); 1267 + } 1268 + 1269 + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { 1270 + /* The specs state to update the NRSSI LT with 1271 + * the value 0x7FFFFFFF here. I think that is some weird 1272 + * compiler optimization in the original driver. 1273 + * Essentially, what we do here is resetting all NRSSI LT 1274 + * entries to -32 (see the limit_value() in nrssi_hw_update()) 1275 + */ 1276 + bcm43xx_nrssi_hw_update(bcm, 0xFFFF); 1277 + bcm43xx_calc_nrssi_threshold(bcm); 1278 + } else if (phy->connected) { 1279 + if (radio->nrssi[0] == -1000) { 1280 + assert(radio->nrssi[1] == -1000); 1281 + bcm43xx_calc_nrssi_slope(bcm); 1282 + } else { 1283 + assert(radio->nrssi[1] != -1000); 1284 + bcm43xx_calc_nrssi_threshold(bcm); 1285 + } 1286 + } 1287 + if (radio->revision == 8) 1288 + bcm43xx_phy_write(bcm, 0x0805, 0x3230); 1289 + bcm43xx_phy_init_pctl(bcm); 1290 + if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) { 1291 + bcm43xx_phy_write(bcm, 0x0429, 1292 + bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF); 1293 + bcm43xx_phy_write(bcm, 0x04C3, 1294 + bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF); 1295 + } 1296 + } 1297 + 1298 + static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) 1299 + { 1300 + int i; 1301 + u16 ret = 0; 1302 + 1303 + for (i = 0; i < 10; i++){ 1304 + bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); 1305 + udelay(1); 1306 + bcm43xx_phy_write(bcm, 0x0015, 0xEFA0); 1307 + udelay(10); 1308 + bcm43xx_phy_write(bcm, 0x0015, 0xFFA0); 1309 + udelay(40); 1310 + ret += bcm43xx_phy_read(bcm, 0x002C); 1311 + } 1312 + 1313 + return ret; 1314 + } 1315 + 1316 + void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) 1317 + { 1318 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1319 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1320 + u16 regstack[12] = { 0 }; 1321 + u16 mls; 1322 + u16 fval; 1323 + int i, j; 1324 + 1325 + regstack[0] = bcm43xx_phy_read(bcm, 0x0015); 1326 + regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0; 1327 + 1328 + if (radio->version == 0x2053) { 1329 + regstack[2] = bcm43xx_phy_read(bcm, 0x000A); 1330 + regstack[3] = bcm43xx_phy_read(bcm, 0x002A); 1331 + regstack[4] = bcm43xx_phy_read(bcm, 0x0035); 1332 + regstack[5] = bcm43xx_phy_read(bcm, 0x0003); 1333 + regstack[6] = bcm43xx_phy_read(bcm, 0x0001); 1334 + regstack[7] = bcm43xx_phy_read(bcm, 0x0030); 1335 + 1336 + regstack[8] = bcm43xx_radio_read16(bcm, 0x0043); 1337 + regstack[9] = bcm43xx_radio_read16(bcm, 0x007A); 1338 + regstack[10] = bcm43xx_read16(bcm, 0x03EC); 1339 + regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0; 1340 + 1341 + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); 1342 + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); 1343 + bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F); 1344 + bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0); 1345 + } 1346 + bcm43xx_phy_write(bcm, 0x0015, 0xB000); 1347 + bcm43xx_phy_write(bcm, 0x002B, 0x0004); 1348 + 1349 + if (radio->version == 0x2053) { 1350 + bcm43xx_phy_write(bcm, 0x002B, 0x0203); 1351 + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); 1352 + } 1353 + 1354 + phy->minlowsig[0] = 0xFFFF; 1355 + 1356 + for (i = 0; i < 4; i++) { 1357 + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); 1358 + bcm43xx_phy_lo_b_r15_loop(bcm); 1359 + } 1360 + for (i = 0; i < 10; i++) { 1361 + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); 1362 + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; 1363 + if (mls < phy->minlowsig[0]) { 1364 + phy->minlowsig[0] = mls; 1365 + phy->minlowsigpos[0] = i; 1366 + } 1367 + } 1368 + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]); 1369 + 1370 + phy->minlowsig[1] = 0xFFFF; 1371 + 1372 + for (i = -4; i < 5; i += 2) { 1373 + for (j = -4; j < 5; j += 2) { 1374 + if (j < 0) 1375 + fval = (0x0100 * i) + j + 0x0100; 1376 + else 1377 + fval = (0x0100 * i) + j; 1378 + bcm43xx_phy_write(bcm, 0x002F, fval); 1379 + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; 1380 + if (mls < phy->minlowsig[1]) { 1381 + phy->minlowsig[1] = mls; 1382 + phy->minlowsigpos[1] = fval; 1383 + } 1384 + } 1385 + } 1386 + phy->minlowsigpos[1] += 0x0101; 1387 + 1388 + bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]); 1389 + if (radio->version == 0x2053) { 1390 + bcm43xx_phy_write(bcm, 0x000A, regstack[2]); 1391 + bcm43xx_phy_write(bcm, 0x002A, regstack[3]); 1392 + bcm43xx_phy_write(bcm, 0x0035, regstack[4]); 1393 + bcm43xx_phy_write(bcm, 0x0003, regstack[5]); 1394 + bcm43xx_phy_write(bcm, 0x0001, regstack[6]); 1395 + bcm43xx_phy_write(bcm, 0x0030, regstack[7]); 1396 + 1397 + bcm43xx_radio_write16(bcm, 0x0043, regstack[8]); 1398 + bcm43xx_radio_write16(bcm, 0x007A, regstack[9]); 1399 + 1400 + bcm43xx_radio_write16(bcm, 0x0052, 1401 + (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F) 1402 + | regstack[11]); 1403 + 1404 + bcm43xx_write16(bcm, 0x03EC, regstack[10]); 1405 + } 1406 + bcm43xx_phy_write(bcm, 0x0015, regstack[0]); 1407 + } 1408 + 1409 + static inline 1410 + u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) 1411 + { 1412 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1413 + 1414 + if (phy->connected) { 1415 + bcm43xx_phy_write(bcm, 0x15, 0xE300); 1416 + control <<= 8; 1417 + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0); 1418 + udelay(5); 1419 + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2); 1420 + udelay(2); 1421 + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3); 1422 + udelay(4); 1423 + bcm43xx_phy_write(bcm, 0x0015, 0xF300); 1424 + udelay(8); 1425 + } else { 1426 + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0); 1427 + udelay(2); 1428 + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0); 1429 + udelay(4); 1430 + bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); 1431 + udelay(8); 1432 + } 1433 + 1434 + return bcm43xx_phy_read(bcm, 0x002D); 1435 + } 1436 + 1437 + static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) 1438 + { 1439 + int i; 1440 + u32 ret = 0; 1441 + 1442 + for (i = 0; i < 8; i++) 1443 + ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control); 1444 + 1445 + return ret; 1446 + } 1447 + 1448 + /* Write the LocalOscillator CONTROL */ 1449 + static inline 1450 + void bcm43xx_lo_write(struct bcm43xx_private *bcm, 1451 + struct bcm43xx_lopair *pair) 1452 + { 1453 + u16 value; 1454 + 1455 + value = (u8)(pair->low); 1456 + value |= ((u8)(pair->high)) << 8; 1457 + 1458 + #ifdef CONFIG_BCM43XX_DEBUG 1459 + /* Sanity check. */ 1460 + if (pair->low < -8 || pair->low > 8 || 1461 + pair->high < -8 || pair->high > 8) { 1462 + printk(KERN_WARNING PFX 1463 + "WARNING: Writing invalid LOpair " 1464 + "(low: %d, high: %d, index: %lu)\n", 1465 + pair->low, pair->high, 1466 + (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs)); 1467 + dump_stack(); 1468 + } 1469 + #endif 1470 + 1471 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value); 1472 + } 1473 + 1474 + static inline 1475 + struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, 1476 + u16 baseband_attenuation, 1477 + u16 radio_attenuation, 1478 + u16 tx) 1479 + { 1480 + static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; 1481 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1482 + 1483 + if (baseband_attenuation > 6) 1484 + baseband_attenuation = 6; 1485 + assert(radio_attenuation < 10); 1486 + 1487 + if (tx == 3) { 1488 + return bcm43xx_get_lopair(phy, 1489 + radio_attenuation, 1490 + baseband_attenuation); 1491 + } 1492 + return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation); 1493 + } 1494 + 1495 + static inline 1496 + struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) 1497 + { 1498 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1499 + 1500 + return bcm43xx_find_lopair(bcm, 1501 + radio->baseband_atten, 1502 + radio->radio_atten, 1503 + radio->txctl1); 1504 + } 1505 + 1506 + /* Adjust B/G LO */ 1507 + void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed) 1508 + { 1509 + struct bcm43xx_lopair *pair; 1510 + 1511 + if (fixed) { 1512 + /* Use fixed values. Only for initialization. */ 1513 + pair = bcm43xx_find_lopair(bcm, 2, 3, 0); 1514 + } else 1515 + pair = bcm43xx_current_lopair(bcm); 1516 + bcm43xx_lo_write(bcm, pair); 1517 + } 1518 + 1519 + static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) 1520 + { 1521 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1522 + u16 txctl2 = 0, i; 1523 + u32 smallest, tmp; 1524 + 1525 + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); 1526 + udelay(10); 1527 + smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0); 1528 + for (i = 0; i < 16; i++) { 1529 + bcm43xx_radio_write16(bcm, 0x0052, i); 1530 + udelay(10); 1531 + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0); 1532 + if (tmp < smallest) { 1533 + smallest = tmp; 1534 + txctl2 = i; 1535 + } 1536 + } 1537 + radio->txctl2 = txctl2; 1538 + } 1539 + 1540 + static 1541 + void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm, 1542 + const struct bcm43xx_lopair *in_pair, 1543 + struct bcm43xx_lopair *out_pair, 1544 + u16 r27) 1545 + { 1546 + static const struct bcm43xx_lopair transitions[8] = { 1547 + { .high = 1, .low = 1, }, 1548 + { .high = 1, .low = 0, }, 1549 + { .high = 1, .low = -1, }, 1550 + { .high = 0, .low = -1, }, 1551 + { .high = -1, .low = -1, }, 1552 + { .high = -1, .low = 0, }, 1553 + { .high = -1, .low = 1, }, 1554 + { .high = 0, .low = 1, }, 1555 + }; 1556 + struct bcm43xx_lopair lowest_transition = { 1557 + .high = in_pair->high, 1558 + .low = in_pair->low, 1559 + }; 1560 + struct bcm43xx_lopair tmp_pair; 1561 + struct bcm43xx_lopair transition; 1562 + int i = 12; 1563 + int state = 0; 1564 + int found_lower; 1565 + int j, begin, end; 1566 + u32 lowest_deviation; 1567 + u32 tmp; 1568 + 1569 + /* Note that in_pair and out_pair can point to the same pair. Be careful. */ 1570 + 1571 + bcm43xx_lo_write(bcm, &lowest_transition); 1572 + lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27); 1573 + do { 1574 + found_lower = 0; 1575 + assert(state >= 0 && state <= 8); 1576 + if (state == 0) { 1577 + begin = 1; 1578 + end = 8; 1579 + } else if (state % 2 == 0) { 1580 + begin = state - 1; 1581 + end = state + 1; 1582 + } else { 1583 + begin = state - 2; 1584 + end = state + 2; 1585 + } 1586 + if (begin < 1) 1587 + begin += 8; 1588 + if (end > 8) 1589 + end -= 8; 1590 + 1591 + j = begin; 1592 + tmp_pair.high = lowest_transition.high; 1593 + tmp_pair.low = lowest_transition.low; 1594 + while (1) { 1595 + assert(j >= 1 && j <= 8); 1596 + transition.high = tmp_pair.high + transitions[j - 1].high; 1597 + transition.low = tmp_pair.low + transitions[j - 1].low; 1598 + if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) { 1599 + bcm43xx_lo_write(bcm, &transition); 1600 + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27); 1601 + if (tmp < lowest_deviation) { 1602 + lowest_deviation = tmp; 1603 + state = j; 1604 + found_lower = 1; 1605 + 1606 + lowest_transition.high = transition.high; 1607 + lowest_transition.low = transition.low; 1608 + } 1609 + } 1610 + if (j == end) 1611 + break; 1612 + if (j == 8) 1613 + j = 1; 1614 + else 1615 + j++; 1616 + } 1617 + } while (i-- && found_lower); 1618 + 1619 + out_pair->high = lowest_transition.high; 1620 + out_pair->low = lowest_transition.low; 1621 + } 1622 + 1623 + /* Set the baseband attenuation value on chip. */ 1624 + void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, 1625 + u16 baseband_attenuation) 1626 + { 1627 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1628 + u16 value; 1629 + 1630 + if (phy->version == 0) { 1631 + value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); 1632 + value |= (baseband_attenuation & 0x000F); 1633 + bcm43xx_write16(bcm, 0x03E6, value); 1634 + return; 1635 + } 1636 + 1637 + if (phy->version > 1) { 1638 + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; 1639 + value |= (baseband_attenuation << 2) & 0x003C; 1640 + } else { 1641 + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078; 1642 + value |= (baseband_attenuation << 3) & 0x0078; 1643 + } 1644 + bcm43xx_phy_write(bcm, 0x0060, value); 1645 + } 1646 + 1647 + /* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ 1648 + void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) 1649 + { 1650 + static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; 1651 + const int is_initializing = bcm43xx_is_initializing(bcm); 1652 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1653 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1654 + u16 h, i, oldi = 0, j; 1655 + struct bcm43xx_lopair control; 1656 + struct bcm43xx_lopair *tmp_control; 1657 + u16 tmp; 1658 + u16 regstack[16] = { 0 }; 1659 + u8 oldchannel; 1660 + 1661 + //XXX: What are these? 1662 + u8 r27 = 0, r31; 1663 + 1664 + oldchannel = radio->channel; 1665 + /* Setup */ 1666 + if (phy->connected) { 1667 + regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); 1668 + regstack[1] = bcm43xx_phy_read(bcm, 0x0802); 1669 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); 1670 + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); 1671 + } 1672 + regstack[3] = bcm43xx_read16(bcm, 0x03E2); 1673 + bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000); 1674 + regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); 1675 + regstack[5] = bcm43xx_phy_read(bcm, 0x15); 1676 + regstack[6] = bcm43xx_phy_read(bcm, 0x2A); 1677 + regstack[7] = bcm43xx_phy_read(bcm, 0x35); 1678 + regstack[8] = bcm43xx_phy_read(bcm, 0x60); 1679 + regstack[9] = bcm43xx_radio_read16(bcm, 0x43); 1680 + regstack[10] = bcm43xx_radio_read16(bcm, 0x7A); 1681 + regstack[11] = bcm43xx_radio_read16(bcm, 0x52); 1682 + if (phy->connected) { 1683 + regstack[12] = bcm43xx_phy_read(bcm, 0x0811); 1684 + regstack[13] = bcm43xx_phy_read(bcm, 0x0812); 1685 + regstack[14] = bcm43xx_phy_read(bcm, 0x0814); 1686 + regstack[15] = bcm43xx_phy_read(bcm, 0x0815); 1687 + } 1688 + bcm43xx_radio_selectchannel(bcm, 6, 0); 1689 + if (phy->connected) { 1690 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); 1691 + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); 1692 + bcm43xx_dummy_transmission(bcm); 1693 + } 1694 + bcm43xx_radio_write16(bcm, 0x0043, 0x0006); 1695 + 1696 + bcm43xx_phy_set_baseband_attenuation(bcm, 2); 1697 + 1698 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000); 1699 + bcm43xx_phy_write(bcm, 0x002E, 0x007F); 1700 + bcm43xx_phy_write(bcm, 0x080F, 0x0078); 1701 + bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7)); 1702 + bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0); 1703 + bcm43xx_phy_write(bcm, 0x002B, 0x0203); 1704 + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); 1705 + if (phy->connected) { 1706 + bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003); 1707 + bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC); 1708 + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); 1709 + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); 1710 + } 1711 + if (is_initializing) 1712 + bcm43xx_phy_lo_g_measure_txctl2(bcm); 1713 + bcm43xx_phy_write(bcm, 0x080F, 0x8078); 1714 + 1715 + /* Measure */ 1716 + control.low = 0; 1717 + control.high = 0; 1718 + for (h = 0; h < 10; h++) { 1719 + /* Loop over each possible RadioAttenuation (0-9) */ 1720 + i = pairorder[h]; 1721 + if (is_initializing) { 1722 + if (i == 3) { 1723 + control.low = 0; 1724 + control.high = 0; 1725 + } else if (((i % 2 == 1) && (oldi % 2 == 1)) || 1726 + ((i % 2 == 0) && (oldi % 2 == 0))) { 1727 + tmp_control = bcm43xx_get_lopair(phy, oldi, 0); 1728 + memcpy(&control, tmp_control, sizeof(control)); 1729 + } else { 1730 + tmp_control = bcm43xx_get_lopair(phy, 3, 0); 1731 + memcpy(&control, tmp_control, sizeof(control)); 1732 + } 1733 + } 1734 + /* Loop over each possible BasebandAttenuation/2 */ 1735 + for (j = 0; j < 4; j++) { 1736 + if (is_initializing) { 1737 + tmp = i * 2 + j; 1738 + r27 = 0; 1739 + r31 = 0; 1740 + if (tmp > 14) { 1741 + r31 = 1; 1742 + if (tmp > 17) 1743 + r27 = 1; 1744 + if (tmp > 19) 1745 + r27 = 2; 1746 + } 1747 + } else { 1748 + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); 1749 + if (!tmp_control->used) 1750 + continue; 1751 + memcpy(&control, tmp_control, sizeof(control)); 1752 + r27 = 3; 1753 + r31 = 0; 1754 + } 1755 + bcm43xx_radio_write16(bcm, 0x43, i); 1756 + bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); 1757 + udelay(10); 1758 + 1759 + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); 1760 + 1761 + tmp = (regstack[10] & 0xFFF0); 1762 + if (r31) 1763 + tmp |= 0x0008; 1764 + bcm43xx_radio_write16(bcm, 0x007A, tmp); 1765 + 1766 + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); 1767 + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); 1768 + } 1769 + oldi = i; 1770 + } 1771 + /* Loop over each possible RadioAttenuation (10-13) */ 1772 + for (i = 10; i < 14; i++) { 1773 + /* Loop over each possible BasebandAttenuation/2 */ 1774 + for (j = 0; j < 4; j++) { 1775 + if (is_initializing) { 1776 + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); 1777 + memcpy(&control, tmp_control, sizeof(control)); 1778 + tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger. 1779 + r27 = 0; 1780 + r31 = 0; 1781 + if (tmp > 14) { 1782 + r31 = 1; 1783 + if (tmp > 17) 1784 + r27 = 1; 1785 + if (tmp > 19) 1786 + r27 = 2; 1787 + } 1788 + } else { 1789 + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); 1790 + if (!tmp_control->used) 1791 + continue; 1792 + memcpy(&control, tmp_control, sizeof(control)); 1793 + r27 = 3; 1794 + r31 = 0; 1795 + } 1796 + bcm43xx_radio_write16(bcm, 0x43, i - 9); 1797 + bcm43xx_radio_write16(bcm, 0x52, 1798 + radio->txctl2 1799 + | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? 1800 + udelay(10); 1801 + 1802 + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); 1803 + 1804 + tmp = (regstack[10] & 0xFFF0); 1805 + if (r31) 1806 + tmp |= 0x0008; 1807 + bcm43xx_radio_write16(bcm, 0x7A, tmp); 1808 + 1809 + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); 1810 + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); 1811 + } 1812 + } 1813 + 1814 + /* Restoration */ 1815 + if (phy->connected) { 1816 + bcm43xx_phy_write(bcm, 0x0015, 0xE300); 1817 + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0); 1818 + udelay(5); 1819 + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); 1820 + udelay(2); 1821 + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); 1822 + } else 1823 + bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); 1824 + bcm43xx_phy_lo_adjust(bcm, is_initializing); 1825 + bcm43xx_phy_write(bcm, 0x002E, 0x807F); 1826 + if (phy->connected) 1827 + bcm43xx_phy_write(bcm, 0x002F, 0x0202); 1828 + else 1829 + bcm43xx_phy_write(bcm, 0x002F, 0x0101); 1830 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]); 1831 + bcm43xx_phy_write(bcm, 0x0015, regstack[5]); 1832 + bcm43xx_phy_write(bcm, 0x002A, regstack[6]); 1833 + bcm43xx_phy_write(bcm, 0x0035, regstack[7]); 1834 + bcm43xx_phy_write(bcm, 0x0060, regstack[8]); 1835 + bcm43xx_radio_write16(bcm, 0x0043, regstack[9]); 1836 + bcm43xx_radio_write16(bcm, 0x007A, regstack[10]); 1837 + regstack[11] &= 0x00F0; 1838 + regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F); 1839 + bcm43xx_radio_write16(bcm, 0x52, regstack[11]); 1840 + bcm43xx_write16(bcm, 0x03E2, regstack[3]); 1841 + if (phy->connected) { 1842 + bcm43xx_phy_write(bcm, 0x0811, regstack[12]); 1843 + bcm43xx_phy_write(bcm, 0x0812, regstack[13]); 1844 + bcm43xx_phy_write(bcm, 0x0814, regstack[14]); 1845 + bcm43xx_phy_write(bcm, 0x0815, regstack[15]); 1846 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]); 1847 + bcm43xx_phy_write(bcm, 0x0802, regstack[1]); 1848 + } 1849 + bcm43xx_radio_selectchannel(bcm, oldchannel, 1); 1850 + 1851 + #ifdef CONFIG_BCM43XX_DEBUG 1852 + { 1853 + /* Sanity check for all lopairs. */ 1854 + for (i = 0; i < BCM43xx_LO_COUNT; i++) { 1855 + tmp_control = phy->_lo_pairs + i; 1856 + if (tmp_control->low < -8 || tmp_control->low > 8 || 1857 + tmp_control->high < -8 || tmp_control->high > 8) { 1858 + printk(KERN_WARNING PFX 1859 + "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n", 1860 + tmp_control->low, tmp_control->high, i); 1861 + } 1862 + } 1863 + } 1864 + #endif /* CONFIG_BCM43XX_DEBUG */ 1865 + } 1866 + 1867 + static 1868 + void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm) 1869 + { 1870 + struct bcm43xx_lopair *pair; 1871 + 1872 + pair = bcm43xx_current_lopair(bcm); 1873 + pair->used = 1; 1874 + } 1875 + 1876 + void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) 1877 + { 1878 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1879 + struct bcm43xx_lopair *pair; 1880 + int i; 1881 + 1882 + for (i = 0; i < BCM43xx_LO_COUNT; i++) { 1883 + pair = phy->_lo_pairs + i; 1884 + pair->used = 0; 1885 + } 1886 + } 1887 + 1888 + /* http://bcm-specs.sipsolutions.net/EstimatePowerOut 1889 + * This function converts a TSSI value to dBm in Q5.2 1890 + */ 1891 + static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) 1892 + { 1893 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1894 + s8 dbm = 0; 1895 + s32 tmp; 1896 + 1897 + tmp = phy->idle_tssi; 1898 + tmp += tssi; 1899 + tmp -= phy->savedpctlreg; 1900 + 1901 + switch (phy->type) { 1902 + case BCM43xx_PHYTYPE_A: 1903 + tmp += 0x80; 1904 + tmp = limit_value(tmp, 0x00, 0xFF); 1905 + dbm = phy->tssi2dbm[tmp]; 1906 + TODO(); //TODO: There's a FIXME on the specs 1907 + break; 1908 + case BCM43xx_PHYTYPE_B: 1909 + case BCM43xx_PHYTYPE_G: 1910 + tmp = limit_value(tmp, 0x00, 0x3F); 1911 + dbm = phy->tssi2dbm[tmp]; 1912 + break; 1913 + default: 1914 + assert(0); 1915 + } 1916 + 1917 + return dbm; 1918 + } 1919 + 1920 + /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ 1921 + void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) 1922 + { 1923 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1924 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1925 + 1926 + if (phy->savedpctlreg == 0xFFFF) 1927 + return; 1928 + if ((bcm->board_type == 0x0416) && 1929 + (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)) 1930 + return; 1931 + 1932 + switch (phy->type) { 1933 + case BCM43xx_PHYTYPE_A: { 1934 + 1935 + TODO(); //TODO: Nothing for A PHYs yet :-/ 1936 + 1937 + break; 1938 + } 1939 + case BCM43xx_PHYTYPE_B: 1940 + case BCM43xx_PHYTYPE_G: { 1941 + u16 tmp; 1942 + u16 txpower; 1943 + s8 v0, v1, v2, v3; 1944 + s8 average; 1945 + u8 max_pwr; 1946 + s16 desired_pwr, estimated_pwr, pwr_adjust; 1947 + s16 radio_att_delta, baseband_att_delta; 1948 + s16 radio_attenuation, baseband_attenuation; 1949 + unsigned long phylock_flags; 1950 + 1951 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058); 1952 + v0 = (s8)(tmp & 0x00FF); 1953 + v1 = (s8)((tmp & 0xFF00) >> 8); 1954 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A); 1955 + v2 = (s8)(tmp & 0x00FF); 1956 + v3 = (s8)((tmp & 0xFF00) >> 8); 1957 + tmp = 0; 1958 + 1959 + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { 1960 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070); 1961 + v0 = (s8)(tmp & 0x00FF); 1962 + v1 = (s8)((tmp & 0xFF00) >> 8); 1963 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072); 1964 + v2 = (s8)(tmp & 0x00FF); 1965 + v3 = (s8)((tmp & 0xFF00) >> 8); 1966 + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) 1967 + return; 1968 + v0 = (v0 + 0x20) & 0x3F; 1969 + v1 = (v1 + 0x20) & 0x3F; 1970 + v2 = (v2 + 0x20) & 0x3F; 1971 + v3 = (v3 + 0x20) & 0x3F; 1972 + tmp = 1; 1973 + } 1974 + bcm43xx_radio_clear_tssi(bcm); 1975 + 1976 + average = (v0 + v1 + v2 + v3 + 2) / 4; 1977 + 1978 + if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8)) 1979 + average -= 13; 1980 + 1981 + estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average); 1982 + 1983 + max_pwr = bcm->sprom.maxpower_bgphy; 1984 + 1985 + if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) && 1986 + (phy->type == BCM43xx_PHYTYPE_G)) 1987 + max_pwr -= 0x3; 1988 + 1989 + /*TODO: 1990 + max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr) 1991 + where REG is the max power as per the regulatory domain 1992 + */ 1993 + 1994 + desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr); 1995 + /* Check if we need to adjust the current power. */ 1996 + pwr_adjust = desired_pwr - estimated_pwr; 1997 + radio_att_delta = -(pwr_adjust + 7) >> 3; 1998 + baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); 1999 + if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { 2000 + bcm43xx_phy_lo_mark_current_used(bcm); 2001 + return; 2002 + } 2003 + 2004 + /* Calculate the new attenuation values. */ 2005 + baseband_attenuation = radio->baseband_atten; 2006 + baseband_attenuation += baseband_att_delta; 2007 + radio_attenuation = radio->radio_atten; 2008 + radio_attenuation += radio_att_delta; 2009 + 2010 + /* Get baseband and radio attenuation values into their permitted ranges. 2011 + * baseband 0-11, radio 0-9. 2012 + * Radio attenuation affects power level 4 times as much as baseband. 2013 + */ 2014 + if (radio_attenuation < 0) { 2015 + baseband_attenuation -= (4 * -radio_attenuation); 2016 + radio_attenuation = 0; 2017 + } else if (radio_attenuation > 9) { 2018 + baseband_attenuation += (4 * (radio_attenuation - 9)); 2019 + radio_attenuation = 9; 2020 + } else { 2021 + while (baseband_attenuation < 0 && radio_attenuation > 0) { 2022 + baseband_attenuation += 4; 2023 + radio_attenuation--; 2024 + } 2025 + while (baseband_attenuation > 11 && radio_attenuation < 9) { 2026 + baseband_attenuation -= 4; 2027 + radio_attenuation++; 2028 + } 2029 + } 2030 + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); 2031 + 2032 + txpower = radio->txctl1; 2033 + if ((radio->version == 0x2050) && (radio->revision == 2)) { 2034 + if (radio_attenuation <= 1) { 2035 + if (txpower == 0) { 2036 + txpower = 3; 2037 + radio_attenuation += 2; 2038 + baseband_attenuation += 2; 2039 + } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { 2040 + baseband_attenuation += 4 * (radio_attenuation - 2); 2041 + radio_attenuation = 2; 2042 + } 2043 + } else if (radio_attenuation > 4 && txpower != 0) { 2044 + txpower = 0; 2045 + if (baseband_attenuation < 3) { 2046 + radio_attenuation -= 3; 2047 + baseband_attenuation += 2; 2048 + } else { 2049 + radio_attenuation -= 2; 2050 + baseband_attenuation -= 2; 2051 + } 2052 + } 2053 + } 2054 + radio->txctl1 = txpower; 2055 + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); 2056 + radio_attenuation = limit_value(radio_attenuation, 0, 9); 2057 + 2058 + bcm43xx_phy_lock(bcm, phylock_flags); 2059 + bcm43xx_radio_lock(bcm); 2060 + bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation, 2061 + radio_attenuation, txpower); 2062 + bcm43xx_phy_lo_mark_current_used(bcm); 2063 + bcm43xx_radio_unlock(bcm); 2064 + bcm43xx_phy_unlock(bcm, phylock_flags); 2065 + break; 2066 + } 2067 + default: 2068 + assert(0); 2069 + } 2070 + } 2071 + 2072 + static inline 2073 + s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den) 2074 + { 2075 + if (num < 0) 2076 + return num/den; 2077 + else 2078 + return (num+den/2)/den; 2079 + } 2080 + 2081 + static inline 2082 + s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) 2083 + { 2084 + s32 m1, m2, f = 256, q, delta; 2085 + s8 i = 0; 2086 + 2087 + m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32); 2088 + m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1); 2089 + do { 2090 + if (i > 15) 2091 + return -EINVAL; 2092 + q = bcm43xx_tssi2dbm_ad(f * 4096 - 2093 + bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048); 2094 + delta = abs(q - f); 2095 + f = q; 2096 + i++; 2097 + } while (delta >= 2); 2098 + entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128); 2099 + return 0; 2100 + } 2101 + 2102 + /* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ 2103 + int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) 2104 + { 2105 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2106 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 2107 + s16 pab0, pab1, pab2; 2108 + u8 idx; 2109 + s8 *dyn_tssi2dbm; 2110 + 2111 + if (phy->type == BCM43xx_PHYTYPE_A) { 2112 + pab0 = (s16)(bcm->sprom.pa1b0); 2113 + pab1 = (s16)(bcm->sprom.pa1b1); 2114 + pab2 = (s16)(bcm->sprom.pa1b2); 2115 + } else { 2116 + pab0 = (s16)(bcm->sprom.pa0b0); 2117 + pab1 = (s16)(bcm->sprom.pa0b1); 2118 + pab2 = (s16)(bcm->sprom.pa0b2); 2119 + } 2120 + 2121 + if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) { 2122 + phy->idle_tssi = 0x34; 2123 + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; 2124 + return 0; 2125 + } 2126 + 2127 + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && 2128 + pab0 != -1 && pab1 != -1 && pab2 != -1) { 2129 + /* The pabX values are set in SPROM. Use them. */ 2130 + if (phy->type == BCM43xx_PHYTYPE_A) { 2131 + if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 && 2132 + (s8)bcm->sprom.idle_tssi_tgt_aphy != -1) 2133 + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy); 2134 + else 2135 + phy->idle_tssi = 62; 2136 + } else { 2137 + if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 && 2138 + (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1) 2139 + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy); 2140 + else 2141 + phy->idle_tssi = 62; 2142 + } 2143 + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); 2144 + if (dyn_tssi2dbm == NULL) { 2145 + printk(KERN_ERR PFX "Could not allocate memory" 2146 + "for tssi2dbm table\n"); 2147 + return -ENOMEM; 2148 + } 2149 + for (idx = 0; idx < 64; idx++) 2150 + if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) { 2151 + phy->tssi2dbm = NULL; 2152 + printk(KERN_ERR PFX "Could not generate " 2153 + "tssi2dBm table\n"); 2154 + return -ENODEV; 2155 + } 2156 + phy->tssi2dbm = dyn_tssi2dbm; 2157 + phy->dyn_tssi_tbl = 1; 2158 + } else { 2159 + /* pabX values not set in SPROM. */ 2160 + switch (phy->type) { 2161 + case BCM43xx_PHYTYPE_A: 2162 + /* APHY needs a generated table. */ 2163 + phy->tssi2dbm = NULL; 2164 + printk(KERN_ERR PFX "Could not generate tssi2dBm " 2165 + "table (wrong SPROM info)!\n"); 2166 + return -ENODEV; 2167 + case BCM43xx_PHYTYPE_B: 2168 + phy->idle_tssi = 0x34; 2169 + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; 2170 + break; 2171 + case BCM43xx_PHYTYPE_G: 2172 + phy->idle_tssi = 0x34; 2173 + phy->tssi2dbm = bcm43xx_tssi2dbm_g_table; 2174 + break; 2175 + } 2176 + } 2177 + 2178 + return 0; 2179 + } 2180 + 2181 + int bcm43xx_phy_init(struct bcm43xx_private *bcm) 2182 + { 2183 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2184 + int err = -ENODEV; 2185 + unsigned long flags; 2186 + 2187 + /* We do not want to be preempted while calibrating 2188 + * the hardware. 2189 + */ 2190 + local_irq_save(flags); 2191 + 2192 + switch (phy->type) { 2193 + case BCM43xx_PHYTYPE_A: 2194 + if (phy->rev == 2 || phy->rev == 3) { 2195 + bcm43xx_phy_inita(bcm); 2196 + err = 0; 2197 + } 2198 + break; 2199 + case BCM43xx_PHYTYPE_B: 2200 + switch (phy->rev) { 2201 + case 2: 2202 + bcm43xx_phy_initb2(bcm); 2203 + err = 0; 2204 + break; 2205 + case 4: 2206 + bcm43xx_phy_initb4(bcm); 2207 + err = 0; 2208 + break; 2209 + case 5: 2210 + bcm43xx_phy_initb5(bcm); 2211 + err = 0; 2212 + break; 2213 + case 6: 2214 + bcm43xx_phy_initb6(bcm); 2215 + err = 0; 2216 + break; 2217 + } 2218 + break; 2219 + case BCM43xx_PHYTYPE_G: 2220 + bcm43xx_phy_initg(bcm); 2221 + err = 0; 2222 + break; 2223 + } 2224 + local_irq_restore(flags); 2225 + if (err) 2226 + printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); 2227 + 2228 + return err; 2229 + } 2230 + 2231 + void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm) 2232 + { 2233 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2234 + u16 antennadiv; 2235 + u16 offset; 2236 + u16 value; 2237 + u32 ucodeflags; 2238 + 2239 + antennadiv = phy->antenna_diversity; 2240 + 2241 + if (antennadiv == 0xFFFF) 2242 + antennadiv = 3; 2243 + assert(antennadiv <= 3); 2244 + 2245 + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 2246 + BCM43xx_UCODEFLAGS_OFFSET); 2247 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 2248 + BCM43xx_UCODEFLAGS_OFFSET, 2249 + ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV); 2250 + 2251 + switch (phy->type) { 2252 + case BCM43xx_PHYTYPE_A: 2253 + case BCM43xx_PHYTYPE_G: 2254 + if (phy->type == BCM43xx_PHYTYPE_A) 2255 + offset = 0x0000; 2256 + else 2257 + offset = 0x0400; 2258 + 2259 + if (antennadiv == 2) 2260 + value = (3/*automatic*/ << 7); 2261 + else 2262 + value = (antennadiv << 7); 2263 + bcm43xx_phy_write(bcm, offset + 1, 2264 + (bcm43xx_phy_read(bcm, offset + 1) 2265 + & 0x7E7F) | value); 2266 + 2267 + if (antennadiv >= 2) { 2268 + if (antennadiv == 2) 2269 + value = (antennadiv << 7); 2270 + else 2271 + value = (0/*force0*/ << 7); 2272 + bcm43xx_phy_write(bcm, offset + 0x2B, 2273 + (bcm43xx_phy_read(bcm, offset + 0x2B) 2274 + & 0xFEFF) | value); 2275 + } 2276 + 2277 + if (phy->type == BCM43xx_PHYTYPE_G) { 2278 + if (antennadiv >= 2) 2279 + bcm43xx_phy_write(bcm, 0x048C, 2280 + bcm43xx_phy_read(bcm, 0x048C) 2281 + | 0x2000); 2282 + else 2283 + bcm43xx_phy_write(bcm, 0x048C, 2284 + bcm43xx_phy_read(bcm, 0x048C) 2285 + & ~0x2000); 2286 + if (phy->rev >= 2) { 2287 + bcm43xx_phy_write(bcm, 0x0461, 2288 + bcm43xx_phy_read(bcm, 0x0461) 2289 + | 0x0010); 2290 + bcm43xx_phy_write(bcm, 0x04AD, 2291 + (bcm43xx_phy_read(bcm, 0x04AD) 2292 + & 0x00FF) | 0x0015); 2293 + if (phy->rev == 2) 2294 + bcm43xx_phy_write(bcm, 0x0427, 0x0008); 2295 + else 2296 + bcm43xx_phy_write(bcm, 0x0427, 2297 + (bcm43xx_phy_read(bcm, 0x0427) 2298 + & 0x00FF) | 0x0008); 2299 + } 2300 + else if (phy->rev >= 6) 2301 + bcm43xx_phy_write(bcm, 0x049B, 0x00DC); 2302 + } else { 2303 + if (phy->rev < 3) 2304 + bcm43xx_phy_write(bcm, 0x002B, 2305 + (bcm43xx_phy_read(bcm, 0x002B) 2306 + & 0x00FF) | 0x0024); 2307 + else { 2308 + bcm43xx_phy_write(bcm, 0x0061, 2309 + bcm43xx_phy_read(bcm, 0x0061) 2310 + | 0x0010); 2311 + if (phy->rev == 3) { 2312 + bcm43xx_phy_write(bcm, 0x0093, 0x001D); 2313 + bcm43xx_phy_write(bcm, 0x0027, 0x0008); 2314 + } else { 2315 + bcm43xx_phy_write(bcm, 0x0093, 0x003A); 2316 + bcm43xx_phy_write(bcm, 0x0027, 2317 + (bcm43xx_phy_read(bcm, 0x0027) 2318 + & 0x00FF) | 0x0008); 2319 + } 2320 + } 2321 + } 2322 + break; 2323 + case BCM43xx_PHYTYPE_B: 2324 + if (bcm->current_core->rev == 2) 2325 + value = (3/*automatic*/ << 7); 2326 + else 2327 + value = (antennadiv << 7); 2328 + bcm43xx_phy_write(bcm, 0x03E2, 2329 + (bcm43xx_phy_read(bcm, 0x03E2) 2330 + & 0xFE7F) | value); 2331 + break; 2332 + default: 2333 + assert(0); 2334 + } 2335 + 2336 + if (antennadiv >= 2) { 2337 + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 2338 + BCM43xx_UCODEFLAGS_OFFSET); 2339 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 2340 + BCM43xx_UCODEFLAGS_OFFSET, 2341 + ucodeflags | BCM43xx_UCODEFLAG_AUTODIV); 2342 + } 2343 + 2344 + phy->antenna_diversity = antennadiv; 2345 + }
+74
drivers/net/wireless/bcm43xx/bcm43xx_phy.h
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #ifndef BCM43xx_PHY_H_ 32 + #define BCM43xx_PHY_H_ 33 + 34 + #include <linux/types.h> 35 + 36 + struct bcm43xx_private; 37 + 38 + void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm); 39 + #define bcm43xx_phy_lock(bcm, flags) \ 40 + do { \ 41 + local_irq_save(flags); \ 42 + bcm43xx_raw_phy_lock(bcm); \ 43 + } while (0) 44 + void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm); 45 + #define bcm43xx_phy_unlock(bcm, flags) \ 46 + do { \ 47 + bcm43xx_raw_phy_unlock(bcm); \ 48 + local_irq_restore(flags); \ 49 + } while (0) 50 + 51 + u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); 52 + void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); 53 + 54 + int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm); 55 + int bcm43xx_phy_init(struct bcm43xx_private *bcm); 56 + 57 + void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm); 58 + void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm); 59 + int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect); 60 + 61 + void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm); 62 + void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm); 63 + void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm); 64 + 65 + /* Adjust the LocalOscillator to the saved values. 66 + * "fixed" is only set to 1 once in initialization. Set to 0 otherwise. 67 + */ 68 + void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed); 69 + void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm); 70 + 71 + void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, 72 + u16 baseband_attenuation); 73 + 74 + #endif /* BCM43xx_PHY_H_ */
+606
drivers/net/wireless/bcm43xx/bcm43xx_pio.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + PIO Transmission 6 + 7 + Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de> 8 + 9 + This program is free software; you can redistribute it and/or modify 10 + it under the terms of the GNU General Public License as published by 11 + the Free Software Foundation; either version 2 of the License, or 12 + (at your option) any later version. 13 + 14 + This program is distributed in the hope that it will be useful, 15 + but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + GNU General Public License for more details. 18 + 19 + You should have received a copy of the GNU General Public License 20 + along with this program; see the file COPYING. If not, write to 21 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 22 + Boston, MA 02110-1301, USA. 23 + 24 + */ 25 + 26 + #include "bcm43xx.h" 27 + #include "bcm43xx_pio.h" 28 + #include "bcm43xx_main.h" 29 + #include "bcm43xx_xmit.h" 30 + 31 + #include <linux/delay.h> 32 + 33 + 34 + static void tx_start(struct bcm43xx_pioqueue *queue) 35 + { 36 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, 37 + BCM43xx_PIO_TXCTL_INIT); 38 + } 39 + 40 + static void tx_octet(struct bcm43xx_pioqueue *queue, 41 + u8 octet) 42 + { 43 + if (queue->need_workarounds) { 44 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, 45 + octet); 46 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, 47 + BCM43xx_PIO_TXCTL_WRITEHI); 48 + } else { 49 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, 50 + BCM43xx_PIO_TXCTL_WRITEHI); 51 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, 52 + octet); 53 + } 54 + } 55 + 56 + static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr, 57 + const u8 *packet, 58 + unsigned int *pos) 59 + { 60 + const u8 *source; 61 + unsigned int i = *pos; 62 + u16 ret; 63 + 64 + if (i < sizeof(*txhdr)) { 65 + source = (const u8 *)txhdr; 66 + } else { 67 + source = packet; 68 + i -= sizeof(*txhdr); 69 + } 70 + ret = le16_to_cpu( *((u16 *)(source + i)) ); 71 + *pos += 2; 72 + 73 + return ret; 74 + } 75 + 76 + static void tx_data(struct bcm43xx_pioqueue *queue, 77 + struct bcm43xx_txhdr *txhdr, 78 + const u8 *packet, 79 + unsigned int octets) 80 + { 81 + u16 data; 82 + unsigned int i = 0; 83 + 84 + if (queue->need_workarounds) { 85 + data = tx_get_next_word(txhdr, packet, &i); 86 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); 87 + } 88 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, 89 + BCM43xx_PIO_TXCTL_WRITELO | 90 + BCM43xx_PIO_TXCTL_WRITEHI); 91 + while (i < octets - 1) { 92 + data = tx_get_next_word(txhdr, packet, &i); 93 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); 94 + } 95 + if (octets % 2) 96 + tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]); 97 + } 98 + 99 + static void tx_complete(struct bcm43xx_pioqueue *queue, 100 + struct sk_buff *skb) 101 + { 102 + if (queue->need_workarounds) { 103 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, 104 + skb->data[skb->len - 1]); 105 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, 106 + BCM43xx_PIO_TXCTL_WRITEHI | 107 + BCM43xx_PIO_TXCTL_COMPLETE); 108 + } else { 109 + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, 110 + BCM43xx_PIO_TXCTL_COMPLETE); 111 + } 112 + } 113 + 114 + static u16 generate_cookie(struct bcm43xx_pioqueue *queue, 115 + int packetindex) 116 + { 117 + u16 cookie = 0x0000; 118 + 119 + /* We use the upper 4 bits for the PIO 120 + * controller ID and the lower 12 bits 121 + * for the packet index (in the cache). 122 + */ 123 + switch (queue->mmio_base) { 124 + case BCM43xx_MMIO_PIO1_BASE: 125 + break; 126 + case BCM43xx_MMIO_PIO2_BASE: 127 + cookie = 0x1000; 128 + break; 129 + case BCM43xx_MMIO_PIO3_BASE: 130 + cookie = 0x2000; 131 + break; 132 + case BCM43xx_MMIO_PIO4_BASE: 133 + cookie = 0x3000; 134 + break; 135 + default: 136 + assert(0); 137 + } 138 + assert(((u16)packetindex & 0xF000) == 0x0000); 139 + cookie |= (u16)packetindex; 140 + 141 + return cookie; 142 + } 143 + 144 + static 145 + struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, 146 + u16 cookie, 147 + struct bcm43xx_pio_txpacket **packet) 148 + { 149 + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); 150 + struct bcm43xx_pioqueue *queue = NULL; 151 + int packetindex; 152 + 153 + switch (cookie & 0xF000) { 154 + case 0x0000: 155 + queue = pio->queue0; 156 + break; 157 + case 0x1000: 158 + queue = pio->queue1; 159 + break; 160 + case 0x2000: 161 + queue = pio->queue2; 162 + break; 163 + case 0x3000: 164 + queue = pio->queue3; 165 + break; 166 + default: 167 + assert(0); 168 + } 169 + packetindex = (cookie & 0x0FFF); 170 + assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); 171 + *packet = &(queue->tx_packets_cache[packetindex]); 172 + 173 + return queue; 174 + } 175 + 176 + static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, 177 + struct sk_buff *skb, 178 + struct bcm43xx_pio_txpacket *packet) 179 + { 180 + struct bcm43xx_txhdr txhdr; 181 + unsigned int octets; 182 + 183 + assert(skb_shinfo(skb)->nr_frags == 0); 184 + bcm43xx_generate_txhdr(queue->bcm, 185 + &txhdr, skb->data, skb->len, 186 + (packet->xmitted_frags == 0), 187 + generate_cookie(queue, pio_txpacket_getindex(packet))); 188 + 189 + tx_start(queue); 190 + octets = skb->len + sizeof(txhdr); 191 + if (queue->need_workarounds) 192 + octets--; 193 + tx_data(queue, &txhdr, (u8 *)skb->data, octets); 194 + tx_complete(queue, skb); 195 + } 196 + 197 + static void free_txpacket(struct bcm43xx_pio_txpacket *packet, 198 + int irq_context) 199 + { 200 + struct bcm43xx_pioqueue *queue = packet->queue; 201 + 202 + ieee80211_txb_free(packet->txb); 203 + list_move(&packet->list, &queue->txfree); 204 + queue->nr_txfree++; 205 + 206 + assert(queue->tx_devq_used >= packet->xmitted_octets); 207 + assert(queue->tx_devq_packets >= packet->xmitted_frags); 208 + queue->tx_devq_used -= packet->xmitted_octets; 209 + queue->tx_devq_packets -= packet->xmitted_frags; 210 + } 211 + 212 + static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) 213 + { 214 + struct bcm43xx_pioqueue *queue = packet->queue; 215 + struct ieee80211_txb *txb = packet->txb; 216 + struct sk_buff *skb; 217 + u16 octets; 218 + int i; 219 + 220 + for (i = packet->xmitted_frags; i < txb->nr_frags; i++) { 221 + skb = txb->fragments[i]; 222 + 223 + octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); 224 + assert(queue->tx_devq_size >= octets); 225 + assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); 226 + assert(queue->tx_devq_used <= queue->tx_devq_size); 227 + /* Check if there is sufficient free space on the device 228 + * TX queue. If not, return and let the TX tasklet 229 + * retry later. 230 + */ 231 + if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) 232 + return -EBUSY; 233 + if (queue->tx_devq_used + octets > queue->tx_devq_size) 234 + return -EBUSY; 235 + /* Now poke the device. */ 236 + pio_tx_write_fragment(queue, skb, packet); 237 + 238 + /* Account for the packet size. 239 + * (We must not overflow the device TX queue) 240 + */ 241 + queue->tx_devq_packets++; 242 + queue->tx_devq_used += octets; 243 + 244 + assert(packet->xmitted_frags <= packet->txb->nr_frags); 245 + packet->xmitted_frags++; 246 + packet->xmitted_octets += octets; 247 + } 248 + list_move_tail(&packet->list, &queue->txrunning); 249 + 250 + return 0; 251 + } 252 + 253 + static void tx_tasklet(unsigned long d) 254 + { 255 + struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d; 256 + struct bcm43xx_private *bcm = queue->bcm; 257 + unsigned long flags; 258 + struct bcm43xx_pio_txpacket *packet, *tmp_packet; 259 + int err; 260 + 261 + bcm43xx_lock_mmio(bcm, flags); 262 + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { 263 + assert(packet->xmitted_frags < packet->txb->nr_frags); 264 + if (packet->xmitted_frags == 0) { 265 + int i; 266 + struct sk_buff *skb; 267 + 268 + /* Check if the device queue is big 269 + * enough for every fragment. If not, drop the 270 + * whole packet. 271 + */ 272 + for (i = 0; i < packet->txb->nr_frags; i++) { 273 + skb = packet->txb->fragments[i]; 274 + if (unlikely(skb->len > queue->tx_devq_size)) { 275 + dprintkl(KERN_ERR PFX "PIO TX device queue too small. " 276 + "Dropping packet.\n"); 277 + free_txpacket(packet, 1); 278 + goto next_packet; 279 + } 280 + } 281 + } 282 + /* Try to transmit the packet. 283 + * This may not completely succeed. 284 + */ 285 + err = pio_tx_packet(packet); 286 + if (err) 287 + break; 288 + next_packet: 289 + continue; 290 + } 291 + bcm43xx_unlock_mmio(bcm, flags); 292 + } 293 + 294 + static void setup_txqueues(struct bcm43xx_pioqueue *queue) 295 + { 296 + struct bcm43xx_pio_txpacket *packet; 297 + int i; 298 + 299 + queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS; 300 + for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { 301 + packet = &(queue->tx_packets_cache[i]); 302 + 303 + packet->queue = queue; 304 + INIT_LIST_HEAD(&packet->list); 305 + 306 + list_add(&packet->list, &queue->txfree); 307 + } 308 + } 309 + 310 + static 311 + struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, 312 + u16 pio_mmio_base) 313 + { 314 + struct bcm43xx_pioqueue *queue; 315 + u32 value; 316 + u16 qsize; 317 + 318 + queue = kzalloc(sizeof(*queue), GFP_KERNEL); 319 + if (!queue) 320 + goto out; 321 + 322 + queue->bcm = bcm; 323 + queue->mmio_base = pio_mmio_base; 324 + queue->need_workarounds = (bcm->current_core->rev < 3); 325 + 326 + INIT_LIST_HEAD(&queue->txfree); 327 + INIT_LIST_HEAD(&queue->txqueue); 328 + INIT_LIST_HEAD(&queue->txrunning); 329 + tasklet_init(&queue->txtask, tx_tasklet, 330 + (unsigned long)queue); 331 + 332 + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 333 + value |= BCM43xx_SBF_XFER_REG_BYTESWAP; 334 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); 335 + 336 + qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); 337 + if (qsize <= BCM43xx_PIO_TXQADJUST) { 338 + printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize); 339 + goto err_freequeue; 340 + } 341 + qsize -= BCM43xx_PIO_TXQADJUST; 342 + queue->tx_devq_size = qsize; 343 + 344 + setup_txqueues(queue); 345 + 346 + out: 347 + return queue; 348 + 349 + err_freequeue: 350 + kfree(queue); 351 + queue = NULL; 352 + goto out; 353 + } 354 + 355 + static void cancel_transfers(struct bcm43xx_pioqueue *queue) 356 + { 357 + struct bcm43xx_pio_txpacket *packet, *tmp_packet; 358 + 359 + netif_tx_disable(queue->bcm->net_dev); 360 + assert(queue->bcm->shutting_down); 361 + tasklet_disable(&queue->txtask); 362 + 363 + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) 364 + free_txpacket(packet, 0); 365 + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) 366 + free_txpacket(packet, 0); 367 + } 368 + 369 + static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) 370 + { 371 + if (!queue) 372 + return; 373 + 374 + cancel_transfers(queue); 375 + kfree(queue); 376 + } 377 + 378 + void bcm43xx_pio_free(struct bcm43xx_private *bcm) 379 + { 380 + struct bcm43xx_pio *pio; 381 + 382 + if (!bcm43xx_using_pio(bcm)) 383 + return; 384 + pio = bcm43xx_current_pio(bcm); 385 + 386 + bcm43xx_destroy_pioqueue(pio->queue3); 387 + pio->queue3 = NULL; 388 + bcm43xx_destroy_pioqueue(pio->queue2); 389 + pio->queue2 = NULL; 390 + bcm43xx_destroy_pioqueue(pio->queue1); 391 + pio->queue1 = NULL; 392 + bcm43xx_destroy_pioqueue(pio->queue0); 393 + pio->queue0 = NULL; 394 + } 395 + 396 + int bcm43xx_pio_init(struct bcm43xx_private *bcm) 397 + { 398 + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); 399 + struct bcm43xx_pioqueue *queue; 400 + int err = -ENOMEM; 401 + 402 + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); 403 + if (!queue) 404 + goto out; 405 + pio->queue0 = queue; 406 + 407 + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); 408 + if (!queue) 409 + goto err_destroy0; 410 + pio->queue1 = queue; 411 + 412 + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); 413 + if (!queue) 414 + goto err_destroy1; 415 + pio->queue2 = queue; 416 + 417 + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); 418 + if (!queue) 419 + goto err_destroy2; 420 + pio->queue3 = queue; 421 + 422 + if (bcm->current_core->rev < 3) 423 + bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; 424 + 425 + dprintk(KERN_INFO PFX "PIO initialized\n"); 426 + err = 0; 427 + out: 428 + return err; 429 + 430 + err_destroy2: 431 + bcm43xx_destroy_pioqueue(pio->queue2); 432 + pio->queue2 = NULL; 433 + err_destroy1: 434 + bcm43xx_destroy_pioqueue(pio->queue1); 435 + pio->queue1 = NULL; 436 + err_destroy0: 437 + bcm43xx_destroy_pioqueue(pio->queue0); 438 + pio->queue0 = NULL; 439 + goto out; 440 + } 441 + 442 + int bcm43xx_pio_tx(struct bcm43xx_private *bcm, 443 + struct ieee80211_txb *txb) 444 + { 445 + struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1; 446 + struct bcm43xx_pio_txpacket *packet; 447 + u16 tmp; 448 + 449 + assert(!queue->tx_suspended); 450 + assert(!list_empty(&queue->txfree)); 451 + 452 + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); 453 + if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) 454 + return -EBUSY; 455 + 456 + packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); 457 + packet->txb = txb; 458 + packet->xmitted_frags = 0; 459 + packet->xmitted_octets = 0; 460 + list_move_tail(&packet->list, &queue->txqueue); 461 + queue->nr_txfree--; 462 + assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS); 463 + 464 + /* Suspend TX, if we are out of packets in the "free" queue. */ 465 + if (unlikely(list_empty(&queue->txfree))) { 466 + netif_stop_queue(queue->bcm->net_dev); 467 + queue->tx_suspended = 1; 468 + } 469 + 470 + tasklet_schedule(&queue->txtask); 471 + 472 + return 0; 473 + } 474 + 475 + void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, 476 + struct bcm43xx_xmitstatus *status) 477 + { 478 + struct bcm43xx_pioqueue *queue; 479 + struct bcm43xx_pio_txpacket *packet; 480 + 481 + queue = parse_cookie(bcm, status->cookie, &packet); 482 + assert(queue); 483 + //TODO 484 + if (!queue) 485 + return; 486 + free_txpacket(packet, 1); 487 + if (unlikely(queue->tx_suspended)) { 488 + queue->tx_suspended = 0; 489 + netif_wake_queue(queue->bcm->net_dev); 490 + } 491 + /* If there are packets on the txqueue, poke the tasklet. */ 492 + if (!list_empty(&queue->txqueue)) 493 + tasklet_schedule(&queue->txtask); 494 + } 495 + 496 + static void pio_rx_error(struct bcm43xx_pioqueue *queue, 497 + int clear_buffers, 498 + const char *error) 499 + { 500 + int i; 501 + 502 + printkl("PIO RX error: %s\n", error); 503 + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, 504 + BCM43xx_PIO_RXCTL_READY); 505 + if (clear_buffers) { 506 + assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE); 507 + for (i = 0; i < 15; i++) { 508 + /* Dummy read. */ 509 + bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); 510 + } 511 + } 512 + } 513 + 514 + void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) 515 + { 516 + u16 preamble[21] = { 0 }; 517 + struct bcm43xx_rxhdr *rxhdr; 518 + u16 tmp, len, rxflags2; 519 + int i, preamble_readwords; 520 + struct sk_buff *skb; 521 + 522 + return; 523 + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); 524 + if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { 525 + dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk. 526 + return; 527 + } 528 + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, 529 + BCM43xx_PIO_RXCTL_DATAAVAILABLE); 530 + 531 + for (i = 0; i < 10; i++) { 532 + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); 533 + if (tmp & BCM43xx_PIO_RXCTL_READY) 534 + goto data_ready; 535 + udelay(10); 536 + } 537 + dprintkl(KERN_ERR PFX "PIO RX timed out\n"); 538 + return; 539 + data_ready: 540 + 541 + //FIXME: endianess in this function. 542 + len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); 543 + if (unlikely(len > 0x700)) { 544 + pio_rx_error(queue, 0, "len > 0x700"); 545 + return; 546 + } 547 + if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { 548 + pio_rx_error(queue, 0, "len == 0"); 549 + return; 550 + } 551 + preamble[0] = cpu_to_le16(len); 552 + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) 553 + preamble_readwords = 14 / sizeof(u16); 554 + else 555 + preamble_readwords = 18 / sizeof(u16); 556 + for (i = 0; i < preamble_readwords; i++) { 557 + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); 558 + preamble[i + 1] = cpu_to_be16(tmp);//FIXME? 559 + } 560 + rxhdr = (struct bcm43xx_rxhdr *)preamble; 561 + rxflags2 = le16_to_cpu(rxhdr->flags2); 562 + if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { 563 + pio_rx_error(queue, 564 + (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE), 565 + "invalid frame"); 566 + return; 567 + } 568 + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { 569 + /* We received an xmit status. */ 570 + struct bcm43xx_hwxmitstatus *hw; 571 + struct bcm43xx_xmitstatus stat; 572 + 573 + hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1); 574 + stat.cookie = le16_to_cpu(hw->cookie); 575 + stat.flags = hw->flags; 576 + stat.cnt1 = hw->cnt1; 577 + stat.cnt2 = hw->cnt2; 578 + stat.seq = le16_to_cpu(hw->seq); 579 + stat.unknown = le16_to_cpu(hw->unknown); 580 + 581 + bcm43xx_debugfs_log_txstat(queue->bcm, &stat); 582 + bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat); 583 + 584 + return; 585 + } 586 + 587 + skb = dev_alloc_skb(len); 588 + if (unlikely(!skb)) { 589 + pio_rx_error(queue, 1, "OOM"); 590 + return; 591 + } 592 + skb_put(skb, len); 593 + for (i = 0; i < len - 1; i += 2) { 594 + tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); 595 + *((u16 *)(skb->data + i)) = tmp; 596 + } 597 + if (len % 2) { 598 + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); 599 + skb->data[len - 1] = (tmp & 0x00FF); 600 + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) 601 + skb->data[0x20] = (tmp & 0xFF00) >> 8; 602 + else 603 + skb->data[0x1E] = (tmp & 0xFF00) >> 8; 604 + } 605 + bcm43xx_rx(queue->bcm, skb, rxhdr); 606 + }
+138
drivers/net/wireless/bcm43xx/bcm43xx_pio.h
··· 1 + #ifndef BCM43xx_PIO_H_ 2 + #define BCM43xx_PIO_H_ 3 + 4 + #include "bcm43xx.h" 5 + 6 + #include <linux/interrupt.h> 7 + #include <linux/list.h> 8 + #include <linux/skbuff.h> 9 + 10 + 11 + #define BCM43xx_PIO_TXCTL 0x00 12 + #define BCM43xx_PIO_TXDATA 0x02 13 + #define BCM43xx_PIO_TXQBUFSIZE 0x04 14 + #define BCM43xx_PIO_RXCTL 0x08 15 + #define BCM43xx_PIO_RXDATA 0x0A 16 + 17 + #define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0) 18 + #define BCM43xx_PIO_TXCTL_WRITELO (1 << 1) 19 + #define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2) 20 + #define BCM43xx_PIO_TXCTL_INIT (1 << 3) 21 + #define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7) 22 + 23 + #define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0) 24 + #define BCM43xx_PIO_RXCTL_READY (1 << 1) 25 + 26 + /* PIO constants */ 27 + #define BCM43xx_PIO_MAXTXDEVQPACKETS 31 28 + #define BCM43xx_PIO_TXQADJUST 80 29 + 30 + /* PIO tuning knobs */ 31 + #define BCM43xx_PIO_MAXTXPACKETS 256 32 + 33 + 34 + 35 + #ifdef CONFIG_BCM43XX_PIO 36 + 37 + 38 + struct bcm43xx_pioqueue; 39 + struct bcm43xx_xmitstatus; 40 + 41 + struct bcm43xx_pio_txpacket { 42 + struct bcm43xx_pioqueue *queue; 43 + struct ieee80211_txb *txb; 44 + struct list_head list; 45 + 46 + u8 xmitted_frags; 47 + u16 xmitted_octets; 48 + }; 49 + 50 + #define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) 51 + 52 + struct bcm43xx_pioqueue { 53 + struct bcm43xx_private *bcm; 54 + u16 mmio_base; 55 + 56 + u8 tx_suspended:1, 57 + need_workarounds:1; /* Workarounds needed for core.rev < 3 */ 58 + 59 + /* Adjusted size of the device internal TX buffer. */ 60 + u16 tx_devq_size; 61 + /* Used octets of the device internal TX buffer. */ 62 + u16 tx_devq_used; 63 + /* Used packet slots in the device internal TX buffer. */ 64 + u8 tx_devq_packets; 65 + /* Packets from the txfree list can 66 + * be taken on incoming TX requests. 67 + */ 68 + struct list_head txfree; 69 + unsigned int nr_txfree; 70 + /* Packets on the txqueue are queued, 71 + * but not completely written to the chip, yet. 72 + */ 73 + struct list_head txqueue; 74 + /* Packets on the txrunning queue are completely 75 + * posted to the device. We are waiting for the txstatus. 76 + */ 77 + struct list_head txrunning; 78 + /* Total number or packets sent. 79 + * (This counter can obviously wrap). 80 + */ 81 + unsigned int nr_tx_packets; 82 + struct tasklet_struct txtask; 83 + struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; 84 + }; 85 + 86 + static inline 87 + u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, 88 + u16 offset) 89 + { 90 + return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); 91 + } 92 + 93 + static inline 94 + void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, 95 + u16 offset, u16 value) 96 + { 97 + bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); 98 + } 99 + 100 + 101 + int bcm43xx_pio_init(struct bcm43xx_private *bcm); 102 + void bcm43xx_pio_free(struct bcm43xx_private *bcm); 103 + 104 + int bcm43xx_pio_tx(struct bcm43xx_private *bcm, 105 + struct ieee80211_txb *txb); 106 + void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, 107 + struct bcm43xx_xmitstatus *status); 108 + void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); 109 + 110 + #else /* CONFIG_BCM43XX_PIO */ 111 + 112 + static inline 113 + int bcm43xx_pio_init(struct bcm43xx_private *bcm) 114 + { 115 + return 0; 116 + } 117 + static inline 118 + void bcm43xx_pio_free(struct bcm43xx_private *bcm) 119 + { 120 + } 121 + static inline 122 + int bcm43xx_pio_tx(struct bcm43xx_private *bcm, 123 + struct ieee80211_txb *txb) 124 + { 125 + return 0; 126 + } 127 + static inline 128 + void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, 129 + struct bcm43xx_xmitstatus *status) 130 + { 131 + } 132 + static inline 133 + void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) 134 + { 135 + } 136 + 137 + #endif /* CONFIG_BCM43XX_PIO */ 138 + #endif /* BCM43xx_PIO_H_ */
+358
drivers/net/wireless/bcm43xx/bcm43xx_power.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #include <linux/delay.h> 32 + 33 + #include "bcm43xx.h" 34 + #include "bcm43xx_power.h" 35 + #include "bcm43xx_main.h" 36 + 37 + 38 + /* Get max/min slowclock frequency 39 + * as described in http://bcm-specs.sipsolutions.net/PowerControl 40 + */ 41 + static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, 42 + int get_max) 43 + { 44 + int limit = 0; 45 + int divisor; 46 + int selection; 47 + int err; 48 + u32 tmp; 49 + struct bcm43xx_coreinfo *old_core; 50 + 51 + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) 52 + goto out; 53 + old_core = bcm->current_core; 54 + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); 55 + if (err) 56 + goto out; 57 + 58 + if (bcm->current_core->rev < 6) { 59 + if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || 60 + (bcm->bustype == BCM43xx_BUSTYPE_SB)) { 61 + selection = 1; 62 + divisor = 32; 63 + } else { 64 + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); 65 + if (err) { 66 + printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); 67 + goto out_switchback; 68 + } 69 + if (tmp & 0x10) { 70 + /* PCI */ 71 + selection = 2; 72 + divisor = 64; 73 + } else { 74 + /* XTAL */ 75 + selection = 1; 76 + divisor = 32; 77 + } 78 + } 79 + } else if (bcm->current_core->rev < 10) { 80 + selection = (tmp & 0x07); 81 + if (selection) { 82 + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); 83 + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); 84 + } else 85 + divisor = 1; 86 + } else { 87 + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); 88 + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); 89 + selection = 1; 90 + } 91 + 92 + switch (selection) { 93 + case 0: 94 + /* LPO */ 95 + if (get_max) 96 + limit = 43000; 97 + else 98 + limit = 25000; 99 + break; 100 + case 1: 101 + /* XTAL */ 102 + if (get_max) 103 + limit = 20200000; 104 + else 105 + limit = 19800000; 106 + break; 107 + case 2: 108 + /* PCI */ 109 + if (get_max) 110 + limit = 34000000; 111 + else 112 + limit = 25000000; 113 + break; 114 + default: 115 + assert(0); 116 + } 117 + limit /= divisor; 118 + 119 + out_switchback: 120 + err = bcm43xx_switch_core(bcm, old_core); 121 + assert(err == 0); 122 + 123 + out: 124 + return limit; 125 + } 126 + 127 + /* init power control 128 + * as described in http://bcm-specs.sipsolutions.net/PowerControl 129 + */ 130 + int bcm43xx_pctl_init(struct bcm43xx_private *bcm) 131 + { 132 + int err, maxfreq; 133 + struct bcm43xx_coreinfo *old_core; 134 + 135 + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) 136 + return 0; 137 + old_core = bcm->current_core; 138 + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); 139 + if (err == -ENODEV) 140 + return 0; 141 + if (err) 142 + goto out; 143 + 144 + maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1); 145 + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY, 146 + (maxfreq * 150 + 999999) / 1000000); 147 + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY, 148 + (maxfreq * 15 + 999999) / 1000000); 149 + 150 + err = bcm43xx_switch_core(bcm, old_core); 151 + assert(err == 0); 152 + 153 + out: 154 + return err; 155 + } 156 + 157 + u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm) 158 + { 159 + u16 delay = 0; 160 + int err; 161 + u32 pll_on_delay; 162 + struct bcm43xx_coreinfo *old_core; 163 + int minfreq; 164 + 165 + if (bcm->bustype != BCM43xx_BUSTYPE_PCI) 166 + goto out; 167 + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) 168 + goto out; 169 + old_core = bcm->current_core; 170 + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); 171 + if (err == -ENODEV) 172 + goto out; 173 + 174 + minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0); 175 + pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY); 176 + delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; 177 + 178 + err = bcm43xx_switch_core(bcm, old_core); 179 + assert(err == 0); 180 + 181 + out: 182 + return delay; 183 + } 184 + 185 + /* set the powercontrol clock 186 + * as described in http://bcm-specs.sipsolutions.net/PowerControl 187 + */ 188 + int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode) 189 + { 190 + int err; 191 + struct bcm43xx_coreinfo *old_core; 192 + u32 tmp; 193 + 194 + old_core = bcm->current_core; 195 + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); 196 + if (err == -ENODEV) 197 + return 0; 198 + if (err) 199 + goto out; 200 + 201 + if (bcm->core_chipcommon.rev < 6) { 202 + if (mode == BCM43xx_PCTL_CLK_FAST) { 203 + err = bcm43xx_pctl_set_crystal(bcm, 1); 204 + if (err) 205 + goto out; 206 + } 207 + } else { 208 + if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) && 209 + (bcm->core_chipcommon.rev < 10)) { 210 + switch (mode) { 211 + case BCM43xx_PCTL_CLK_FAST: 212 + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); 213 + tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL; 214 + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); 215 + break; 216 + case BCM43xx_PCTL_CLK_SLOW: 217 + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); 218 + tmp |= BCM43xx_PCTL_FORCE_SLOW; 219 + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); 220 + break; 221 + case BCM43xx_PCTL_CLK_DYNAMIC: 222 + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); 223 + tmp &= ~BCM43xx_PCTL_FORCE_SLOW; 224 + tmp |= BCM43xx_PCTL_FORCE_PLL; 225 + tmp &= ~BCM43xx_PCTL_DYN_XTAL; 226 + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); 227 + } 228 + } 229 + } 230 + 231 + err = bcm43xx_switch_core(bcm, old_core); 232 + assert(err == 0); 233 + 234 + out: 235 + return err; 236 + } 237 + 238 + int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on) 239 + { 240 + int err; 241 + u32 in, out, outenable; 242 + 243 + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in); 244 + if (err) 245 + goto err_pci; 246 + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out); 247 + if (err) 248 + goto err_pci; 249 + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable); 250 + if (err) 251 + goto err_pci; 252 + 253 + outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); 254 + 255 + if (on) { 256 + if (in & 0x40) 257 + return 0; 258 + 259 + out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); 260 + 261 + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); 262 + if (err) 263 + goto err_pci; 264 + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); 265 + if (err) 266 + goto err_pci; 267 + udelay(1000); 268 + 269 + out &= ~BCM43xx_PCTL_PLL_POWERDOWN; 270 + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); 271 + if (err) 272 + goto err_pci; 273 + udelay(5000); 274 + } else { 275 + if (bcm->current_core->rev < 5) 276 + return 0; 277 + if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW) 278 + return 0; 279 + 280 + /* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time? 281 + * err = bcm43xx_switch_core(bcm, bcm->active_80211_core); 282 + * if (err) 283 + * return err; 284 + * if (((bcm->current_core->rev >= 3) && 285 + * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) || 286 + * ((bcm->current_core->rev < 3) && 287 + * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4)))) 288 + * return 0; 289 + * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); 290 + * if (err) 291 + * return err; 292 + */ 293 + 294 + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); 295 + if (err) 296 + goto out; 297 + out &= ~BCM43xx_PCTL_XTAL_POWERUP; 298 + out |= BCM43xx_PCTL_PLL_POWERDOWN; 299 + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); 300 + if (err) 301 + goto err_pci; 302 + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); 303 + if (err) 304 + goto err_pci; 305 + } 306 + 307 + out: 308 + return err; 309 + 310 + err_pci: 311 + printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n"); 312 + err = -EBUSY; 313 + goto out; 314 + } 315 + 316 + /* Set the PowerSavingControlBits. 317 + * Bitvalues: 318 + * 0 => unset the bit 319 + * 1 => set the bit 320 + * -1 => calculate the bit 321 + */ 322 + void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, 323 + int bit25, int bit26) 324 + { 325 + int i; 326 + u32 status; 327 + 328 + //FIXME: Force 25 to off and 26 to on for now: 329 + bit25 = 0; 330 + bit26 = 1; 331 + 332 + if (bit25 == -1) { 333 + //TODO: If powersave is not off and FIXME is not set and we are not in adhoc 334 + // and thus is not an AP and we are associated, set bit 25 335 + } 336 + if (bit26 == -1) { 337 + //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, 338 + // or we are associated, or FIXME, or the latest PS-Poll packet sent was 339 + // successful, set bit26 340 + } 341 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 342 + if (bit25) 343 + status |= BCM43xx_SBF_PS1; 344 + else 345 + status &= ~BCM43xx_SBF_PS1; 346 + if (bit26) 347 + status |= BCM43xx_SBF_PS2; 348 + else 349 + status &= ~BCM43xx_SBF_PS2; 350 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); 351 + if (bit26 && bcm->current_core->rev >= 5) { 352 + for (i = 0; i < 100; i++) { 353 + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4) 354 + break; 355 + udelay(10); 356 + } 357 + } 358 + }
+47
drivers/net/wireless/bcm43xx/bcm43xx_power.h
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #ifndef BCM43xx_POWER_H_ 32 + #define BCM43xx_POWER_H_ 33 + 34 + #include <linux/types.h> 35 + 36 + 37 + struct bcm43xx_private; 38 + 39 + int bcm43xx_pctl_init(struct bcm43xx_private *bcm); 40 + int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode); 41 + int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on); 42 + u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm); 43 + 44 + void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, 45 + int bit25, int bit26); 46 + 47 + #endif /* BCM43xx_POWER_H_ */
+2026
drivers/net/wireless/bcm43xx/bcm43xx_radio.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #include <linux/delay.h> 32 + 33 + #include "bcm43xx.h" 34 + #include "bcm43xx_main.h" 35 + #include "bcm43xx_phy.h" 36 + #include "bcm43xx_radio.h" 37 + #include "bcm43xx_ilt.h" 38 + 39 + 40 + /* Table for bcm43xx_radio_calibrationvalue() */ 41 + static const u16 rcc_table[16] = { 42 + 0x0002, 0x0003, 0x0001, 0x000F, 43 + 0x0006, 0x0007, 0x0005, 0x000F, 44 + 0x000A, 0x000B, 0x0009, 0x000F, 45 + 0x000E, 0x000F, 0x000D, 0x000F, 46 + }; 47 + 48 + /* Reverse the bits of a 4bit value. 49 + * Example: 1101 is flipped 1011 50 + */ 51 + static u16 flip_4bit(u16 value) 52 + { 53 + u16 flipped = 0x0000; 54 + 55 + assert((value & ~0x000F) == 0x0000); 56 + 57 + flipped |= (value & 0x0001) << 3; 58 + flipped |= (value & 0x0002) << 1; 59 + flipped |= (value & 0x0004) >> 1; 60 + flipped |= (value & 0x0008) >> 3; 61 + 62 + return flipped; 63 + } 64 + 65 + /* Get the freq, as it has to be written to the device. */ 66 + static inline 67 + u16 channel2freq_bg(u8 channel) 68 + { 69 + /* Frequencies are given as frequencies_bg[index] + 2.4GHz 70 + * Starting with channel 1 71 + */ 72 + static const u16 frequencies_bg[14] = { 73 + 12, 17, 22, 27, 74 + 32, 37, 42, 47, 75 + 52, 57, 62, 67, 76 + 72, 84, 77 + }; 78 + 79 + assert(channel >= 1 && channel <= 14); 80 + 81 + return frequencies_bg[channel - 1]; 82 + } 83 + 84 + /* Get the freq, as it has to be written to the device. */ 85 + static inline 86 + u16 channel2freq_a(u8 channel) 87 + { 88 + assert(channel <= 200); 89 + 90 + return (5000 + 5 * channel); 91 + } 92 + 93 + void bcm43xx_radio_lock(struct bcm43xx_private *bcm) 94 + { 95 + u32 status; 96 + 97 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 98 + status |= BCM43xx_SBF_RADIOREG_LOCK; 99 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); 100 + mmiowb(); 101 + udelay(10); 102 + } 103 + 104 + void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) 105 + { 106 + u32 status; 107 + 108 + bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */ 109 + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); 110 + status &= ~BCM43xx_SBF_RADIOREG_LOCK; 111 + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); 112 + mmiowb(); 113 + } 114 + 115 + u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) 116 + { 117 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 118 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 119 + 120 + switch (phy->type) { 121 + case BCM43xx_PHYTYPE_A: 122 + offset |= 0x0040; 123 + break; 124 + case BCM43xx_PHYTYPE_B: 125 + if (radio->version == 0x2053) { 126 + if (offset < 0x70) 127 + offset += 0x80; 128 + else if (offset < 0x80) 129 + offset += 0x70; 130 + } else if (radio->version == 0x2050) { 131 + offset |= 0x80; 132 + } else 133 + assert(0); 134 + break; 135 + case BCM43xx_PHYTYPE_G: 136 + offset |= 0x80; 137 + break; 138 + } 139 + 140 + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); 141 + return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); 142 + } 143 + 144 + void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) 145 + { 146 + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); 147 + mmiowb(); 148 + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val); 149 + } 150 + 151 + static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, 152 + s16 first, s16 second, s16 third) 153 + { 154 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 155 + u16 i; 156 + u16 start = 0x08, end = 0x18; 157 + u16 offset = 0x0400; 158 + u16 tmp; 159 + 160 + if (phy->rev <= 1) { 161 + offset = 0x5000; 162 + start = 0x10; 163 + end = 0x20; 164 + } 165 + 166 + for (i = 0; i < 4; i++) 167 + bcm43xx_ilt_write(bcm, offset + i, first); 168 + 169 + for (i = start; i < end; i++) 170 + bcm43xx_ilt_write(bcm, offset + i, second); 171 + 172 + if (third != -1) { 173 + tmp = ((u16)third << 14) | ((u16)third << 6); 174 + bcm43xx_phy_write(bcm, 0x04A0, 175 + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp); 176 + bcm43xx_phy_write(bcm, 0x04A1, 177 + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp); 178 + bcm43xx_phy_write(bcm, 0x04A2, 179 + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp); 180 + } 181 + bcm43xx_dummy_transmission(bcm); 182 + } 183 + 184 + static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) 185 + { 186 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 187 + u16 i, tmp; 188 + u16 offset = 0x0400; 189 + u16 start = 0x0008, end = 0x0018; 190 + 191 + if (phy->rev <= 1) { 192 + offset = 0x5000; 193 + start = 0x0010; 194 + end = 0x0020; 195 + } 196 + 197 + for (i = 0; i < 4; i++) { 198 + tmp = (i & 0xFFFC); 199 + tmp |= (i & 0x0001) << 1; 200 + tmp |= (i & 0x0002) >> 1; 201 + 202 + bcm43xx_ilt_write(bcm, offset + i, tmp); 203 + } 204 + 205 + for (i = start; i < end; i++) 206 + bcm43xx_ilt_write(bcm, offset + i, i - start); 207 + 208 + bcm43xx_phy_write(bcm, 0x04A0, 209 + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040); 210 + bcm43xx_phy_write(bcm, 0x04A1, 211 + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040); 212 + bcm43xx_phy_write(bcm, 0x04A2, 213 + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000); 214 + bcm43xx_dummy_transmission(bcm); 215 + } 216 + 217 + /* Synthetic PU workaround */ 218 + static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) 219 + { 220 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 221 + 222 + if (radio->version != 0x2050 || radio->revision >= 6) { 223 + /* We do not need the workaround. */ 224 + return; 225 + } 226 + 227 + if (channel <= 10) { 228 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, 229 + channel2freq_bg(channel + 4)); 230 + } else { 231 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, 232 + channel2freq_bg(1)); 233 + } 234 + udelay(100); 235 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, 236 + channel2freq_bg(channel)); 237 + } 238 + 239 + u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) 240 + { 241 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 242 + u8 ret = 0; 243 + u16 saved, rssi, temp; 244 + int i, j = 0; 245 + 246 + saved = bcm43xx_phy_read(bcm, 0x0403); 247 + bcm43xx_radio_selectchannel(bcm, channel, 0); 248 + bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5); 249 + if (radio->aci_hw_rssi) 250 + rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F; 251 + else 252 + rssi = saved & 0x3F; 253 + /* clamp temp to signed 5bit */ 254 + if (rssi > 32) 255 + rssi -= 64; 256 + for (i = 0;i < 100; i++) { 257 + temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F; 258 + if (temp > 32) 259 + temp -= 64; 260 + if (temp < rssi) 261 + j++; 262 + if (j >= 20) 263 + ret = 1; 264 + } 265 + bcm43xx_phy_write(bcm, 0x0403, saved); 266 + 267 + return ret; 268 + } 269 + 270 + u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) 271 + { 272 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 273 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 274 + u8 ret[13]; 275 + unsigned int channel = radio->channel; 276 + unsigned int i, j, start, end; 277 + unsigned long phylock_flags; 278 + 279 + if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0))) 280 + return 0; 281 + 282 + bcm43xx_phy_lock(bcm, phylock_flags); 283 + bcm43xx_radio_lock(bcm); 284 + bcm43xx_phy_write(bcm, 0x0802, 285 + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); 286 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 287 + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); 288 + bcm43xx_set_all_gains(bcm, 3, 8, 1); 289 + 290 + start = (channel - 5 > 0) ? channel - 5 : 1; 291 + end = (channel + 5 < 14) ? channel + 5 : 13; 292 + 293 + for (i = start; i <= end; i++) { 294 + if (abs(channel - i) > 2) 295 + ret[i-1] = bcm43xx_radio_aci_detect(bcm, i); 296 + } 297 + bcm43xx_radio_selectchannel(bcm, channel, 0); 298 + bcm43xx_phy_write(bcm, 0x0802, 299 + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003); 300 + bcm43xx_phy_write(bcm, 0x0403, 301 + bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8); 302 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 303 + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); 304 + bcm43xx_set_original_gains(bcm); 305 + for (i = 0; i < 13; i++) { 306 + if (!ret[i]) 307 + continue; 308 + end = (i + 5 < 13) ? i + 5 : 13; 309 + for (j = i; j < end; j++) 310 + ret[j] = 1; 311 + } 312 + bcm43xx_radio_unlock(bcm); 313 + bcm43xx_phy_unlock(bcm, phylock_flags); 314 + 315 + return ret[channel - 1]; 316 + } 317 + 318 + /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ 319 + void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val) 320 + { 321 + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); 322 + mmiowb(); 323 + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val); 324 + } 325 + 326 + /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ 327 + s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset) 328 + { 329 + u16 val; 330 + 331 + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); 332 + val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA); 333 + 334 + return (s16)val; 335 + } 336 + 337 + /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ 338 + void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val) 339 + { 340 + u16 i; 341 + s16 tmp; 342 + 343 + for (i = 0; i < 64; i++) { 344 + tmp = bcm43xx_nrssi_hw_read(bcm, i); 345 + tmp -= val; 346 + tmp = limit_value(tmp, -32, 31); 347 + bcm43xx_nrssi_hw_write(bcm, i, tmp); 348 + } 349 + } 350 + 351 + /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ 352 + void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm) 353 + { 354 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 355 + s16 i, delta; 356 + s32 tmp; 357 + 358 + delta = 0x1F - radio->nrssi[0]; 359 + for (i = 0; i < 64; i++) { 360 + tmp = (i - delta) * radio->nrssislope; 361 + tmp /= 0x10000; 362 + tmp += 0x3A; 363 + tmp = limit_value(tmp, 0, 0x3F); 364 + radio->nrssi_lt[i] = tmp; 365 + } 366 + } 367 + 368 + static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) 369 + { 370 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 371 + u16 backup[20] = { 0 }; 372 + s16 v47F; 373 + u16 i; 374 + u16 saved = 0xFFFF; 375 + 376 + backup[0] = bcm43xx_phy_read(bcm, 0x0001); 377 + backup[1] = bcm43xx_phy_read(bcm, 0x0811); 378 + backup[2] = bcm43xx_phy_read(bcm, 0x0812); 379 + backup[3] = bcm43xx_phy_read(bcm, 0x0814); 380 + backup[4] = bcm43xx_phy_read(bcm, 0x0815); 381 + backup[5] = bcm43xx_phy_read(bcm, 0x005A); 382 + backup[6] = bcm43xx_phy_read(bcm, 0x0059); 383 + backup[7] = bcm43xx_phy_read(bcm, 0x0058); 384 + backup[8] = bcm43xx_phy_read(bcm, 0x000A); 385 + backup[9] = bcm43xx_phy_read(bcm, 0x0003); 386 + backup[10] = bcm43xx_radio_read16(bcm, 0x007A); 387 + backup[11] = bcm43xx_radio_read16(bcm, 0x0043); 388 + 389 + bcm43xx_phy_write(bcm, 0x0429, 390 + bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF); 391 + bcm43xx_phy_write(bcm, 0x0001, 392 + (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000); 393 + bcm43xx_phy_write(bcm, 0x0811, 394 + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); 395 + bcm43xx_phy_write(bcm, 0x0812, 396 + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004); 397 + bcm43xx_phy_write(bcm, 0x0802, 398 + bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2)); 399 + if (phy->rev >= 6) { 400 + backup[12] = bcm43xx_phy_read(bcm, 0x002E); 401 + backup[13] = bcm43xx_phy_read(bcm, 0x002F); 402 + backup[14] = bcm43xx_phy_read(bcm, 0x080F); 403 + backup[15] = bcm43xx_phy_read(bcm, 0x0810); 404 + backup[16] = bcm43xx_phy_read(bcm, 0x0801); 405 + backup[17] = bcm43xx_phy_read(bcm, 0x0060); 406 + backup[18] = bcm43xx_phy_read(bcm, 0x0014); 407 + backup[19] = bcm43xx_phy_read(bcm, 0x0478); 408 + 409 + bcm43xx_phy_write(bcm, 0x002E, 0); 410 + bcm43xx_phy_write(bcm, 0x002F, 0); 411 + bcm43xx_phy_write(bcm, 0x080F, 0); 412 + bcm43xx_phy_write(bcm, 0x0810, 0); 413 + bcm43xx_phy_write(bcm, 0x0478, 414 + bcm43xx_phy_read(bcm, 0x0478) | 0x0100); 415 + bcm43xx_phy_write(bcm, 0x0801, 416 + bcm43xx_phy_read(bcm, 0x0801) | 0x0040); 417 + bcm43xx_phy_write(bcm, 0x0060, 418 + bcm43xx_phy_read(bcm, 0x0060) | 0x0040); 419 + bcm43xx_phy_write(bcm, 0x0014, 420 + bcm43xx_phy_read(bcm, 0x0014) | 0x0200); 421 + } 422 + bcm43xx_radio_write16(bcm, 0x007A, 423 + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); 424 + bcm43xx_radio_write16(bcm, 0x007A, 425 + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); 426 + udelay(30); 427 + 428 + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); 429 + if (v47F >= 0x20) 430 + v47F -= 0x40; 431 + if (v47F == 31) { 432 + for (i = 7; i >= 4; i--) { 433 + bcm43xx_radio_write16(bcm, 0x007B, i); 434 + udelay(20); 435 + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); 436 + if (v47F >= 0x20) 437 + v47F -= 0x40; 438 + if (v47F < 31 && saved == 0xFFFF) 439 + saved = i; 440 + } 441 + if (saved == 0xFFFF) 442 + saved = 4; 443 + } else { 444 + bcm43xx_radio_write16(bcm, 0x007A, 445 + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); 446 + bcm43xx_phy_write(bcm, 0x0814, 447 + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); 448 + bcm43xx_phy_write(bcm, 0x0815, 449 + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); 450 + bcm43xx_phy_write(bcm, 0x0811, 451 + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); 452 + bcm43xx_phy_write(bcm, 0x0812, 453 + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); 454 + bcm43xx_phy_write(bcm, 0x0811, 455 + bcm43xx_phy_read(bcm, 0x0811) | 0x0030); 456 + bcm43xx_phy_write(bcm, 0x0812, 457 + bcm43xx_phy_read(bcm, 0x0812) | 0x0030); 458 + bcm43xx_phy_write(bcm, 0x005A, 0x0480); 459 + bcm43xx_phy_write(bcm, 0x0059, 0x0810); 460 + bcm43xx_phy_write(bcm, 0x0058, 0x000D); 461 + if (phy->rev == 0) { 462 + bcm43xx_phy_write(bcm, 0x0003, 0x0122); 463 + } else { 464 + bcm43xx_phy_write(bcm, 0x000A, 465 + bcm43xx_phy_read(bcm, 0x000A) 466 + | 0x2000); 467 + } 468 + bcm43xx_phy_write(bcm, 0x0814, 469 + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); 470 + bcm43xx_phy_write(bcm, 0x0815, 471 + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); 472 + bcm43xx_phy_write(bcm, 0x0003, 473 + (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F) 474 + | 0x0040); 475 + bcm43xx_radio_write16(bcm, 0x007A, 476 + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); 477 + bcm43xx_set_all_gains(bcm, 3, 0, 1); 478 + bcm43xx_radio_write16(bcm, 0x0043, 479 + (bcm43xx_radio_read16(bcm, 0x0043) 480 + & 0x00F0) | 0x000F); 481 + udelay(30); 482 + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); 483 + if (v47F >= 0x20) 484 + v47F -= 0x40; 485 + if (v47F == -32) { 486 + for (i = 0; i < 4; i++) { 487 + bcm43xx_radio_write16(bcm, 0x007B, i); 488 + udelay(20); 489 + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); 490 + if (v47F >= 0x20) 491 + v47F -= 0x40; 492 + if (v47F > -31 && saved == 0xFFFF) 493 + saved = i; 494 + } 495 + if (saved == 0xFFFF) 496 + saved = 3; 497 + } else 498 + saved = 0; 499 + } 500 + bcm43xx_radio_write16(bcm, 0x007B, saved); 501 + 502 + if (phy->rev >= 6) { 503 + bcm43xx_phy_write(bcm, 0x002E, backup[12]); 504 + bcm43xx_phy_write(bcm, 0x002F, backup[13]); 505 + bcm43xx_phy_write(bcm, 0x080F, backup[14]); 506 + bcm43xx_phy_write(bcm, 0x0810, backup[15]); 507 + } 508 + bcm43xx_phy_write(bcm, 0x0814, backup[3]); 509 + bcm43xx_phy_write(bcm, 0x0815, backup[4]); 510 + bcm43xx_phy_write(bcm, 0x005A, backup[5]); 511 + bcm43xx_phy_write(bcm, 0x0059, backup[6]); 512 + bcm43xx_phy_write(bcm, 0x0058, backup[7]); 513 + bcm43xx_phy_write(bcm, 0x000A, backup[8]); 514 + bcm43xx_phy_write(bcm, 0x0003, backup[9]); 515 + bcm43xx_radio_write16(bcm, 0x0043, backup[11]); 516 + bcm43xx_radio_write16(bcm, 0x007A, backup[10]); 517 + bcm43xx_phy_write(bcm, 0x0802, 518 + bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2); 519 + bcm43xx_phy_write(bcm, 0x0429, 520 + bcm43xx_phy_read(bcm, 0x0429) | 0x8000); 521 + bcm43xx_set_original_gains(bcm); 522 + if (phy->rev >= 6) { 523 + bcm43xx_phy_write(bcm, 0x0801, backup[16]); 524 + bcm43xx_phy_write(bcm, 0x0060, backup[17]); 525 + bcm43xx_phy_write(bcm, 0x0014, backup[18]); 526 + bcm43xx_phy_write(bcm, 0x0478, backup[19]); 527 + } 528 + bcm43xx_phy_write(bcm, 0x0001, backup[0]); 529 + bcm43xx_phy_write(bcm, 0x0812, backup[2]); 530 + bcm43xx_phy_write(bcm, 0x0811, backup[1]); 531 + } 532 + 533 + void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) 534 + { 535 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 536 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 537 + u16 backup[18] = { 0 }; 538 + u16 tmp; 539 + s16 nrssi0, nrssi1; 540 + 541 + switch (phy->type) { 542 + case BCM43xx_PHYTYPE_B: 543 + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); 544 + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); 545 + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); 546 + backup[3] = bcm43xx_phy_read(bcm, 0x0030); 547 + backup[4] = bcm43xx_phy_read(bcm, 0x0026); 548 + backup[5] = bcm43xx_phy_read(bcm, 0x0015); 549 + backup[6] = bcm43xx_phy_read(bcm, 0x002A); 550 + backup[7] = bcm43xx_phy_read(bcm, 0x0020); 551 + backup[8] = bcm43xx_phy_read(bcm, 0x005A); 552 + backup[9] = bcm43xx_phy_read(bcm, 0x0059); 553 + backup[10] = bcm43xx_phy_read(bcm, 0x0058); 554 + backup[11] = bcm43xx_read16(bcm, 0x03E2); 555 + backup[12] = bcm43xx_read16(bcm, 0x03E6); 556 + backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); 557 + 558 + tmp = bcm43xx_radio_read16(bcm, 0x007A); 559 + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; 560 + bcm43xx_radio_write16(bcm, 0x007A, tmp); 561 + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); 562 + bcm43xx_write16(bcm, 0x03EC, 0x7F7F); 563 + bcm43xx_phy_write(bcm, 0x0026, 0x0000); 564 + bcm43xx_phy_write(bcm, 0x0015, 565 + bcm43xx_phy_read(bcm, 0x0015) | 0x0020); 566 + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); 567 + bcm43xx_radio_write16(bcm, 0x007A, 568 + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); 569 + 570 + nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027); 571 + bcm43xx_radio_write16(bcm, 0x007A, 572 + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); 573 + if (phy->rev >= 2) { 574 + bcm43xx_write16(bcm, 0x03E6, 0x0040); 575 + } else if (phy->rev == 0) { 576 + bcm43xx_write16(bcm, 0x03E6, 0x0122); 577 + } else { 578 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 579 + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000); 580 + } 581 + bcm43xx_phy_write(bcm, 0x0020, 0x3F3F); 582 + bcm43xx_phy_write(bcm, 0x0015, 0xF330); 583 + bcm43xx_radio_write16(bcm, 0x005A, 0x0060); 584 + bcm43xx_radio_write16(bcm, 0x0043, 585 + bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0); 586 + bcm43xx_phy_write(bcm, 0x005A, 0x0480); 587 + bcm43xx_phy_write(bcm, 0x0059, 0x0810); 588 + bcm43xx_phy_write(bcm, 0x0058, 0x000D); 589 + udelay(20); 590 + 591 + nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027); 592 + bcm43xx_phy_write(bcm, 0x0030, backup[3]); 593 + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); 594 + bcm43xx_write16(bcm, 0x03E2, backup[11]); 595 + bcm43xx_phy_write(bcm, 0x0026, backup[4]); 596 + bcm43xx_phy_write(bcm, 0x0015, backup[5]); 597 + bcm43xx_phy_write(bcm, 0x002A, backup[6]); 598 + bcm43xx_synth_pu_workaround(bcm, radio->channel); 599 + if (phy->rev != 0) 600 + bcm43xx_write16(bcm, 0x03F4, backup[13]); 601 + 602 + bcm43xx_phy_write(bcm, 0x0020, backup[7]); 603 + bcm43xx_phy_write(bcm, 0x005A, backup[8]); 604 + bcm43xx_phy_write(bcm, 0x0059, backup[9]); 605 + bcm43xx_phy_write(bcm, 0x0058, backup[10]); 606 + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); 607 + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); 608 + 609 + if (nrssi0 == nrssi1) 610 + radio->nrssislope = 0x00010000; 611 + else 612 + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); 613 + 614 + if (nrssi0 <= -4) { 615 + radio->nrssi[0] = nrssi0; 616 + radio->nrssi[1] = nrssi1; 617 + } 618 + break; 619 + case BCM43xx_PHYTYPE_G: 620 + if (radio->revision >= 9) 621 + return; 622 + if (radio->revision == 8) 623 + bcm43xx_calc_nrssi_offset(bcm); 624 + 625 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 626 + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); 627 + bcm43xx_phy_write(bcm, 0x0802, 628 + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); 629 + backup[7] = bcm43xx_read16(bcm, 0x03E2); 630 + bcm43xx_write16(bcm, 0x03E2, 631 + bcm43xx_read16(bcm, 0x03E2) | 0x8000); 632 + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); 633 + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); 634 + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); 635 + backup[3] = bcm43xx_phy_read(bcm, 0x0015); 636 + backup[4] = bcm43xx_phy_read(bcm, 0x005A); 637 + backup[5] = bcm43xx_phy_read(bcm, 0x0059); 638 + backup[6] = bcm43xx_phy_read(bcm, 0x0058); 639 + backup[8] = bcm43xx_read16(bcm, 0x03E6); 640 + backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); 641 + if (phy->rev >= 3) { 642 + backup[10] = bcm43xx_phy_read(bcm, 0x002E); 643 + backup[11] = bcm43xx_phy_read(bcm, 0x002F); 644 + backup[12] = bcm43xx_phy_read(bcm, 0x080F); 645 + backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL); 646 + backup[14] = bcm43xx_phy_read(bcm, 0x0801); 647 + backup[15] = bcm43xx_phy_read(bcm, 0x0060); 648 + backup[16] = bcm43xx_phy_read(bcm, 0x0014); 649 + backup[17] = bcm43xx_phy_read(bcm, 0x0478); 650 + bcm43xx_phy_write(bcm, 0x002E, 0); 651 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0); 652 + switch (phy->rev) { 653 + case 4: case 6: case 7: 654 + bcm43xx_phy_write(bcm, 0x0478, 655 + bcm43xx_phy_read(bcm, 0x0478) 656 + | 0x0100); 657 + bcm43xx_phy_write(bcm, 0x0801, 658 + bcm43xx_phy_read(bcm, 0x0801) 659 + | 0x0040); 660 + break; 661 + case 3: case 5: 662 + bcm43xx_phy_write(bcm, 0x0801, 663 + bcm43xx_phy_read(bcm, 0x0801) 664 + & 0xFFBF); 665 + break; 666 + } 667 + bcm43xx_phy_write(bcm, 0x0060, 668 + bcm43xx_phy_read(bcm, 0x0060) 669 + | 0x0040); 670 + bcm43xx_phy_write(bcm, 0x0014, 671 + bcm43xx_phy_read(bcm, 0x0014) 672 + | 0x0200); 673 + } 674 + bcm43xx_radio_write16(bcm, 0x007A, 675 + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); 676 + bcm43xx_set_all_gains(bcm, 0, 8, 0); 677 + bcm43xx_radio_write16(bcm, 0x007A, 678 + bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7); 679 + if (phy->rev >= 2) { 680 + bcm43xx_phy_write(bcm, 0x0811, 681 + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030); 682 + bcm43xx_phy_write(bcm, 0x0812, 683 + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010); 684 + } 685 + bcm43xx_radio_write16(bcm, 0x007A, 686 + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); 687 + udelay(20); 688 + 689 + nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); 690 + if (nrssi0 >= 0x0020) 691 + nrssi0 -= 0x0040; 692 + 693 + bcm43xx_radio_write16(bcm, 0x007A, 694 + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); 695 + if (phy->rev >= 2) { 696 + bcm43xx_phy_write(bcm, 0x0003, 697 + (bcm43xx_phy_read(bcm, 0x0003) 698 + & 0xFF9F) | 0x0040); 699 + } 700 + 701 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 702 + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) 703 + | 0x2000); 704 + bcm43xx_radio_write16(bcm, 0x007A, 705 + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); 706 + bcm43xx_phy_write(bcm, 0x0015, 0xF330); 707 + if (phy->rev >= 2) { 708 + bcm43xx_phy_write(bcm, 0x0812, 709 + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020); 710 + bcm43xx_phy_write(bcm, 0x0811, 711 + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020); 712 + } 713 + 714 + bcm43xx_set_all_gains(bcm, 3, 0, 1); 715 + if (radio->revision == 8) { 716 + bcm43xx_radio_write16(bcm, 0x0043, 0x001F); 717 + } else { 718 + tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F; 719 + bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060); 720 + tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0; 721 + bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009); 722 + } 723 + bcm43xx_phy_write(bcm, 0x005A, 0x0480); 724 + bcm43xx_phy_write(bcm, 0x0059, 0x0810); 725 + bcm43xx_phy_write(bcm, 0x0058, 0x000D); 726 + udelay(20); 727 + nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); 728 + if (nrssi1 >= 0x0020) 729 + nrssi1 -= 0x0040; 730 + if (nrssi0 == nrssi1) 731 + radio->nrssislope = 0x00010000; 732 + else 733 + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); 734 + if (nrssi0 >= -4) { 735 + radio->nrssi[0] = nrssi1; 736 + radio->nrssi[1] = nrssi0; 737 + } 738 + if (phy->rev >= 3) { 739 + bcm43xx_phy_write(bcm, 0x002E, backup[10]); 740 + bcm43xx_phy_write(bcm, 0x002F, backup[11]); 741 + bcm43xx_phy_write(bcm, 0x080F, backup[12]); 742 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]); 743 + } 744 + if (phy->rev >= 2) { 745 + bcm43xx_phy_write(bcm, 0x0812, 746 + bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF); 747 + bcm43xx_phy_write(bcm, 0x0811, 748 + bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF); 749 + } 750 + 751 + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); 752 + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); 753 + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); 754 + bcm43xx_write16(bcm, 0x03E2, backup[7]); 755 + bcm43xx_write16(bcm, 0x03E6, backup[8]); 756 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]); 757 + bcm43xx_phy_write(bcm, 0x0015, backup[3]); 758 + bcm43xx_phy_write(bcm, 0x005A, backup[4]); 759 + bcm43xx_phy_write(bcm, 0x0059, backup[5]); 760 + bcm43xx_phy_write(bcm, 0x0058, backup[6]); 761 + bcm43xx_synth_pu_workaround(bcm, radio->channel); 762 + bcm43xx_phy_write(bcm, 0x0802, 763 + bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002)); 764 + bcm43xx_set_original_gains(bcm); 765 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 766 + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); 767 + if (phy->rev >= 3) { 768 + bcm43xx_phy_write(bcm, 0x0801, backup[14]); 769 + bcm43xx_phy_write(bcm, 0x0060, backup[15]); 770 + bcm43xx_phy_write(bcm, 0x0014, backup[16]); 771 + bcm43xx_phy_write(bcm, 0x0478, backup[17]); 772 + } 773 + bcm43xx_nrssi_mem_update(bcm); 774 + bcm43xx_calc_nrssi_threshold(bcm); 775 + break; 776 + default: 777 + assert(0); 778 + } 779 + } 780 + 781 + void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) 782 + { 783 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 784 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 785 + s32 threshold; 786 + s32 a, b; 787 + s16 tmp16; 788 + u16 tmp_u16; 789 + 790 + switch (phy->type) { 791 + case BCM43xx_PHYTYPE_B: { 792 + if (radio->version != 0x2050) 793 + return; 794 + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) 795 + return; 796 + 797 + if (radio->revision >= 6) { 798 + threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32; 799 + threshold += 20 * (radio->nrssi[0] + 1); 800 + threshold /= 40; 801 + } else 802 + threshold = radio->nrssi[1] - 5; 803 + 804 + threshold = limit_value(threshold, 0, 0x3E); 805 + bcm43xx_phy_read(bcm, 0x0020); /* dummy read */ 806 + bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C); 807 + 808 + if (radio->revision >= 6) { 809 + bcm43xx_phy_write(bcm, 0x0087, 0x0E0D); 810 + bcm43xx_phy_write(bcm, 0x0086, 0x0C0B); 811 + bcm43xx_phy_write(bcm, 0x0085, 0x0A09); 812 + bcm43xx_phy_write(bcm, 0x0084, 0x0808); 813 + bcm43xx_phy_write(bcm, 0x0083, 0x0808); 814 + bcm43xx_phy_write(bcm, 0x0082, 0x0604); 815 + bcm43xx_phy_write(bcm, 0x0081, 0x0302); 816 + bcm43xx_phy_write(bcm, 0x0080, 0x0100); 817 + } 818 + break; 819 + } 820 + case BCM43xx_PHYTYPE_G: 821 + if (!phy->connected || 822 + !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { 823 + tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20); 824 + if (tmp16 >= 0x20) 825 + tmp16 -= 0x40; 826 + if (tmp16 < 3) { 827 + bcm43xx_phy_write(bcm, 0x048A, 828 + (bcm43xx_phy_read(bcm, 0x048A) 829 + & 0xF000) | 0x09EB); 830 + } else { 831 + bcm43xx_phy_write(bcm, 0x048A, 832 + (bcm43xx_phy_read(bcm, 0x048A) 833 + & 0xF000) | 0x0AED); 834 + } 835 + } else { 836 + if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { 837 + a = 0xE; 838 + b = 0xA; 839 + } else if (!radio->aci_wlan_automatic && radio->aci_enable) { 840 + a = 0x13; 841 + b = 0x12; 842 + } else { 843 + a = 0xE; 844 + b = 0x11; 845 + } 846 + 847 + a = a * (radio->nrssi[1] - radio->nrssi[0]); 848 + a += (radio->nrssi[0] << 6); 849 + if (a < 32) 850 + a += 31; 851 + else 852 + a += 32; 853 + a = a >> 6; 854 + a = limit_value(a, -31, 31); 855 + 856 + b = b * (radio->nrssi[1] - radio->nrssi[0]); 857 + b += (radio->nrssi[0] << 6); 858 + if (b < 32) 859 + b += 31; 860 + else 861 + b += 32; 862 + b = b >> 6; 863 + b = limit_value(b, -31, 31); 864 + 865 + tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000; 866 + tmp_u16 |= ((u32)b & 0x0000003F); 867 + tmp_u16 |= (((u32)a & 0x0000003F) << 6); 868 + bcm43xx_phy_write(bcm, 0x048A, tmp_u16); 869 + } 870 + break; 871 + default: 872 + assert(0); 873 + } 874 + } 875 + 876 + /* Stack implementation to save/restore values from the 877 + * interference mitigation code. 878 + * It is save to restore values in random order. 879 + */ 880 + static void _stack_save(u32 *_stackptr, size_t *stackidx, 881 + u8 id, u16 offset, u16 value) 882 + { 883 + u32 *stackptr = &(_stackptr[*stackidx]); 884 + 885 + assert((offset & 0xF000) == 0x0000); 886 + assert((id & 0xF0) == 0x00); 887 + *stackptr = offset; 888 + *stackptr |= ((u32)id) << 12; 889 + *stackptr |= ((u32)value) << 16; 890 + (*stackidx)++; 891 + assert(*stackidx < BCM43xx_INTERFSTACK_SIZE); 892 + } 893 + 894 + static u16 _stack_restore(u32 *stackptr, 895 + u8 id, u16 offset) 896 + { 897 + size_t i; 898 + 899 + assert((offset & 0xF000) == 0x0000); 900 + assert((id & 0xF0) == 0x00); 901 + for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) { 902 + if ((*stackptr & 0x00000FFF) != offset) 903 + continue; 904 + if (((*stackptr & 0x0000F000) >> 12) != id) 905 + continue; 906 + return ((*stackptr & 0xFFFF0000) >> 16); 907 + } 908 + assert(0); 909 + 910 + return 0; 911 + } 912 + 913 + #define phy_stacksave(offset) \ 914 + do { \ 915 + _stack_save(stack, &stackidx, 0x1, (offset), \ 916 + bcm43xx_phy_read(bcm, (offset))); \ 917 + } while (0) 918 + #define phy_stackrestore(offset) \ 919 + do { \ 920 + bcm43xx_phy_write(bcm, (offset), \ 921 + _stack_restore(stack, 0x1, \ 922 + (offset))); \ 923 + } while (0) 924 + #define radio_stacksave(offset) \ 925 + do { \ 926 + _stack_save(stack, &stackidx, 0x2, (offset), \ 927 + bcm43xx_radio_read16(bcm, (offset))); \ 928 + } while (0) 929 + #define radio_stackrestore(offset) \ 930 + do { \ 931 + bcm43xx_radio_write16(bcm, (offset), \ 932 + _stack_restore(stack, 0x2, \ 933 + (offset))); \ 934 + } while (0) 935 + #define ilt_stacksave(offset) \ 936 + do { \ 937 + _stack_save(stack, &stackidx, 0x3, (offset), \ 938 + bcm43xx_ilt_read(bcm, (offset))); \ 939 + } while (0) 940 + #define ilt_stackrestore(offset) \ 941 + do { \ 942 + bcm43xx_ilt_write(bcm, (offset), \ 943 + _stack_restore(stack, 0x3, \ 944 + (offset))); \ 945 + } while (0) 946 + 947 + static void 948 + bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, 949 + int mode) 950 + { 951 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 952 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 953 + u16 tmp, flipped; 954 + u32 tmp32; 955 + size_t stackidx = 0; 956 + u32 *stack = radio->interfstack; 957 + 958 + switch (mode) { 959 + case BCM43xx_RADIO_INTERFMODE_NONWLAN: 960 + if (phy->rev != 1) { 961 + bcm43xx_phy_write(bcm, 0x042B, 962 + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); 963 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 964 + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000); 965 + break; 966 + } 967 + radio_stacksave(0x0078); 968 + tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); 969 + flipped = flip_4bit(tmp); 970 + if (flipped < 10 && flipped >= 8) 971 + flipped = 7; 972 + else if (flipped >= 10) 973 + flipped -= 3; 974 + flipped = flip_4bit(flipped); 975 + flipped = (flipped << 1) | 0x0020; 976 + bcm43xx_radio_write16(bcm, 0x0078, flipped); 977 + 978 + bcm43xx_calc_nrssi_threshold(bcm); 979 + 980 + phy_stacksave(0x0406); 981 + bcm43xx_phy_write(bcm, 0x0406, 0x7E28); 982 + 983 + bcm43xx_phy_write(bcm, 0x042B, 984 + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); 985 + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, 986 + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000); 987 + 988 + phy_stacksave(0x04A0); 989 + bcm43xx_phy_write(bcm, 0x04A0, 990 + (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008); 991 + phy_stacksave(0x04A1); 992 + bcm43xx_phy_write(bcm, 0x04A1, 993 + (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605); 994 + phy_stacksave(0x04A2); 995 + bcm43xx_phy_write(bcm, 0x04A2, 996 + (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204); 997 + phy_stacksave(0x04A8); 998 + bcm43xx_phy_write(bcm, 0x04A8, 999 + (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803); 1000 + phy_stacksave(0x04AB); 1001 + bcm43xx_phy_write(bcm, 0x04AB, 1002 + (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605); 1003 + 1004 + phy_stacksave(0x04A7); 1005 + bcm43xx_phy_write(bcm, 0x04A7, 0x0002); 1006 + phy_stacksave(0x04A3); 1007 + bcm43xx_phy_write(bcm, 0x04A3, 0x287A); 1008 + phy_stacksave(0x04A9); 1009 + bcm43xx_phy_write(bcm, 0x04A9, 0x2027); 1010 + phy_stacksave(0x0493); 1011 + bcm43xx_phy_write(bcm, 0x0493, 0x32F5); 1012 + phy_stacksave(0x04AA); 1013 + bcm43xx_phy_write(bcm, 0x04AA, 0x2027); 1014 + phy_stacksave(0x04AC); 1015 + bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); 1016 + break; 1017 + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: 1018 + if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800) 1019 + break; 1020 + 1021 + radio->aci_enable = 1; 1022 + 1023 + phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD); 1024 + phy_stacksave(BCM43xx_PHY_G_CRS); 1025 + if (phy->rev < 2) { 1026 + phy_stacksave(0x0406); 1027 + } else { 1028 + phy_stacksave(0x04C0); 1029 + phy_stacksave(0x04C1); 1030 + } 1031 + phy_stacksave(0x0033); 1032 + phy_stacksave(0x04A7); 1033 + phy_stacksave(0x04A3); 1034 + phy_stacksave(0x04A9); 1035 + phy_stacksave(0x04AA); 1036 + phy_stacksave(0x04AC); 1037 + phy_stacksave(0x0493); 1038 + phy_stacksave(0x04A1); 1039 + phy_stacksave(0x04A0); 1040 + phy_stacksave(0x04A2); 1041 + phy_stacksave(0x048A); 1042 + phy_stacksave(0x04A8); 1043 + phy_stacksave(0x04AB); 1044 + if (phy->rev == 2) { 1045 + phy_stacksave(0x04AD); 1046 + phy_stacksave(0x04AE); 1047 + } else if (phy->rev >= 3) { 1048 + phy_stacksave(0x04AD); 1049 + phy_stacksave(0x0415); 1050 + phy_stacksave(0x0416); 1051 + phy_stacksave(0x0417); 1052 + ilt_stacksave(0x1A00 + 0x2); 1053 + ilt_stacksave(0x1A00 + 0x3); 1054 + } 1055 + phy_stacksave(0x042B); 1056 + phy_stacksave(0x048C); 1057 + 1058 + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, 1059 + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) 1060 + & ~0x1000); 1061 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 1062 + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) 1063 + & 0xFFFC) | 0x0002); 1064 + 1065 + bcm43xx_phy_write(bcm, 0x0033, 0x0800); 1066 + bcm43xx_phy_write(bcm, 0x04A3, 0x2027); 1067 + bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8); 1068 + bcm43xx_phy_write(bcm, 0x0493, 0x287A); 1069 + bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8); 1070 + bcm43xx_phy_write(bcm, 0x04AC, 0x287A); 1071 + 1072 + bcm43xx_phy_write(bcm, 0x04A0, 1073 + (bcm43xx_phy_read(bcm, 0x04A0) 1074 + & 0xFFC0) | 0x001A); 1075 + bcm43xx_phy_write(bcm, 0x04A7, 0x000D); 1076 + 1077 + if (phy->rev < 2) { 1078 + bcm43xx_phy_write(bcm, 0x0406, 0xFF0D); 1079 + } else if (phy->rev == 2) { 1080 + bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF); 1081 + bcm43xx_phy_write(bcm, 0x04C1, 0x00A9); 1082 + } else { 1083 + bcm43xx_phy_write(bcm, 0x04C0, 0x00C1); 1084 + bcm43xx_phy_write(bcm, 0x04C1, 0x0059); 1085 + } 1086 + 1087 + bcm43xx_phy_write(bcm, 0x04A1, 1088 + (bcm43xx_phy_read(bcm, 0x04A1) 1089 + & 0xC0FF) | 0x1800); 1090 + bcm43xx_phy_write(bcm, 0x04A1, 1091 + (bcm43xx_phy_read(bcm, 0x04A1) 1092 + & 0xFFC0) | 0x0015); 1093 + bcm43xx_phy_write(bcm, 0x04A8, 1094 + (bcm43xx_phy_read(bcm, 0x04A8) 1095 + & 0xCFFF) | 0x1000); 1096 + bcm43xx_phy_write(bcm, 0x04A8, 1097 + (bcm43xx_phy_read(bcm, 0x04A8) 1098 + & 0xF0FF) | 0x0A00); 1099 + bcm43xx_phy_write(bcm, 0x04AB, 1100 + (bcm43xx_phy_read(bcm, 0x04AB) 1101 + & 0xCFFF) | 0x1000); 1102 + bcm43xx_phy_write(bcm, 0x04AB, 1103 + (bcm43xx_phy_read(bcm, 0x04AB) 1104 + & 0xF0FF) | 0x0800); 1105 + bcm43xx_phy_write(bcm, 0x04AB, 1106 + (bcm43xx_phy_read(bcm, 0x04AB) 1107 + & 0xFFCF) | 0x0010); 1108 + bcm43xx_phy_write(bcm, 0x04AB, 1109 + (bcm43xx_phy_read(bcm, 0x04AB) 1110 + & 0xFFF0) | 0x0005); 1111 + bcm43xx_phy_write(bcm, 0x04A8, 1112 + (bcm43xx_phy_read(bcm, 0x04A8) 1113 + & 0xFFCF) | 0x0010); 1114 + bcm43xx_phy_write(bcm, 0x04A8, 1115 + (bcm43xx_phy_read(bcm, 0x04A8) 1116 + & 0xFFF0) | 0x0006); 1117 + bcm43xx_phy_write(bcm, 0x04A2, 1118 + (bcm43xx_phy_read(bcm, 0x04A2) 1119 + & 0xF0FF) | 0x0800); 1120 + bcm43xx_phy_write(bcm, 0x04A0, 1121 + (bcm43xx_phy_read(bcm, 0x04A0) 1122 + & 0xF0FF) | 0x0500); 1123 + bcm43xx_phy_write(bcm, 0x04A2, 1124 + (bcm43xx_phy_read(bcm, 0x04A2) 1125 + & 0xFFF0) | 0x000B); 1126 + 1127 + if (phy->rev >= 3) { 1128 + bcm43xx_phy_write(bcm, 0x048A, 1129 + bcm43xx_phy_read(bcm, 0x048A) 1130 + & ~0x8000); 1131 + bcm43xx_phy_write(bcm, 0x0415, 1132 + (bcm43xx_phy_read(bcm, 0x0415) 1133 + & 0x8000) | 0x36D8); 1134 + bcm43xx_phy_write(bcm, 0x0416, 1135 + (bcm43xx_phy_read(bcm, 0x0416) 1136 + & 0x8000) | 0x36D8); 1137 + bcm43xx_phy_write(bcm, 0x0417, 1138 + (bcm43xx_phy_read(bcm, 0x0417) 1139 + & 0xFE00) | 0x016D); 1140 + } else { 1141 + bcm43xx_phy_write(bcm, 0x048A, 1142 + bcm43xx_phy_read(bcm, 0x048A) 1143 + | 0x1000); 1144 + bcm43xx_phy_write(bcm, 0x048A, 1145 + (bcm43xx_phy_read(bcm, 0x048A) 1146 + & 0x9FFF) | 0x2000); 1147 + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 1148 + BCM43xx_UCODEFLAGS_OFFSET); 1149 + if (!(tmp32 & 0x800)) { 1150 + tmp32 |= 0x800; 1151 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 1152 + BCM43xx_UCODEFLAGS_OFFSET, 1153 + tmp32); 1154 + } 1155 + } 1156 + if (phy->rev >= 2) { 1157 + bcm43xx_phy_write(bcm, 0x042B, 1158 + bcm43xx_phy_read(bcm, 0x042B) 1159 + | 0x0800); 1160 + } 1161 + bcm43xx_phy_write(bcm, 0x048C, 1162 + (bcm43xx_phy_read(bcm, 0x048C) 1163 + & 0xF0FF) | 0x0200); 1164 + if (phy->rev == 2) { 1165 + bcm43xx_phy_write(bcm, 0x04AE, 1166 + (bcm43xx_phy_read(bcm, 0x04AE) 1167 + & 0xFF00) | 0x007F); 1168 + bcm43xx_phy_write(bcm, 0x04AD, 1169 + (bcm43xx_phy_read(bcm, 0x04AD) 1170 + & 0x00FF) | 0x1300); 1171 + } else if (phy->rev >= 6) { 1172 + bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F); 1173 + bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F); 1174 + bcm43xx_phy_write(bcm, 0x04AD, 1175 + bcm43xx_phy_read(bcm, 0x04AD) 1176 + & 0x00FF); 1177 + } 1178 + bcm43xx_calc_nrssi_slope(bcm); 1179 + break; 1180 + default: 1181 + assert(0); 1182 + } 1183 + } 1184 + 1185 + static void 1186 + bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, 1187 + int mode) 1188 + { 1189 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1190 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1191 + u32 tmp32; 1192 + u32 *stack = radio->interfstack; 1193 + 1194 + switch (mode) { 1195 + case BCM43xx_RADIO_INTERFMODE_NONWLAN: 1196 + if (phy->rev != 1) { 1197 + bcm43xx_phy_write(bcm, 0x042B, 1198 + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); 1199 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 1200 + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); 1201 + break; 1202 + } 1203 + phy_stackrestore(0x0078); 1204 + bcm43xx_calc_nrssi_threshold(bcm); 1205 + phy_stackrestore(0x0406); 1206 + bcm43xx_phy_write(bcm, 0x042B, 1207 + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); 1208 + if (!bcm->bad_frames_preempt) { 1209 + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, 1210 + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) 1211 + & ~(1 << 11)); 1212 + } 1213 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 1214 + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); 1215 + phy_stackrestore(0x04A0); 1216 + phy_stackrestore(0x04A1); 1217 + phy_stackrestore(0x04A2); 1218 + phy_stackrestore(0x04A8); 1219 + phy_stackrestore(0x04AB); 1220 + phy_stackrestore(0x04A7); 1221 + phy_stackrestore(0x04A3); 1222 + phy_stackrestore(0x04A9); 1223 + phy_stackrestore(0x0493); 1224 + phy_stackrestore(0x04AA); 1225 + phy_stackrestore(0x04AC); 1226 + break; 1227 + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: 1228 + if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800)) 1229 + break; 1230 + 1231 + radio->aci_enable = 0; 1232 + 1233 + phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD); 1234 + phy_stackrestore(BCM43xx_PHY_G_CRS); 1235 + phy_stackrestore(0x0033); 1236 + phy_stackrestore(0x04A3); 1237 + phy_stackrestore(0x04A9); 1238 + phy_stackrestore(0x0493); 1239 + phy_stackrestore(0x04AA); 1240 + phy_stackrestore(0x04AC); 1241 + phy_stackrestore(0x04A0); 1242 + phy_stackrestore(0x04A7); 1243 + if (phy->rev >= 2) { 1244 + phy_stackrestore(0x04C0); 1245 + phy_stackrestore(0x04C1); 1246 + } else 1247 + phy_stackrestore(0x0406); 1248 + phy_stackrestore(0x04A1); 1249 + phy_stackrestore(0x04AB); 1250 + phy_stackrestore(0x04A8); 1251 + if (phy->rev == 2) { 1252 + phy_stackrestore(0x04AD); 1253 + phy_stackrestore(0x04AE); 1254 + } else if (phy->rev >= 3) { 1255 + phy_stackrestore(0x04AD); 1256 + phy_stackrestore(0x0415); 1257 + phy_stackrestore(0x0416); 1258 + phy_stackrestore(0x0417); 1259 + ilt_stackrestore(0x1A00 + 0x2); 1260 + ilt_stackrestore(0x1A00 + 0x3); 1261 + } 1262 + phy_stackrestore(0x04A2); 1263 + phy_stackrestore(0x04A8); 1264 + phy_stackrestore(0x042B); 1265 + phy_stackrestore(0x048C); 1266 + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 1267 + BCM43xx_UCODEFLAGS_OFFSET); 1268 + if (tmp32 & 0x800) { 1269 + tmp32 &= ~0x800; 1270 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 1271 + BCM43xx_UCODEFLAGS_OFFSET, 1272 + tmp32); 1273 + } 1274 + bcm43xx_calc_nrssi_slope(bcm); 1275 + break; 1276 + default: 1277 + assert(0); 1278 + } 1279 + } 1280 + 1281 + #undef phy_stacksave 1282 + #undef phy_stackrestore 1283 + #undef radio_stacksave 1284 + #undef radio_stackrestore 1285 + #undef ilt_stacksave 1286 + #undef ilt_stackrestore 1287 + 1288 + int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, 1289 + int mode) 1290 + { 1291 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1292 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1293 + int currentmode; 1294 + 1295 + if ((phy->type != BCM43xx_PHYTYPE_G) || 1296 + (phy->rev == 0) || 1297 + (!phy->connected)) 1298 + return -ENODEV; 1299 + 1300 + radio->aci_wlan_automatic = 0; 1301 + switch (mode) { 1302 + case BCM43xx_RADIO_INTERFMODE_AUTOWLAN: 1303 + radio->aci_wlan_automatic = 1; 1304 + if (radio->aci_enable) 1305 + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; 1306 + else 1307 + mode = BCM43xx_RADIO_INTERFMODE_NONE; 1308 + break; 1309 + case BCM43xx_RADIO_INTERFMODE_NONE: 1310 + case BCM43xx_RADIO_INTERFMODE_NONWLAN: 1311 + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: 1312 + break; 1313 + default: 1314 + return -EINVAL; 1315 + } 1316 + 1317 + currentmode = radio->interfmode; 1318 + if (currentmode == mode) 1319 + return 0; 1320 + if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE) 1321 + bcm43xx_radio_interference_mitigation_disable(bcm, currentmode); 1322 + 1323 + if (mode == BCM43xx_RADIO_INTERFMODE_NONE) { 1324 + radio->aci_enable = 0; 1325 + radio->aci_hw_rssi = 0; 1326 + } else 1327 + bcm43xx_radio_interference_mitigation_enable(bcm, mode); 1328 + radio->interfmode = mode; 1329 + 1330 + return 0; 1331 + } 1332 + 1333 + u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) 1334 + { 1335 + u16 reg, index, ret; 1336 + 1337 + reg = bcm43xx_radio_read16(bcm, 0x0060); 1338 + index = (reg & 0x001E) >> 1; 1339 + ret = rcc_table[index] << 1; 1340 + ret |= (reg & 0x0001); 1341 + ret |= 0x0020; 1342 + 1343 + return ret; 1344 + } 1345 + 1346 + u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) 1347 + { 1348 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1349 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1350 + u16 backup[19] = { 0 }; 1351 + u16 ret; 1352 + u16 i, j; 1353 + u32 tmp1 = 0, tmp2 = 0; 1354 + 1355 + backup[0] = bcm43xx_radio_read16(bcm, 0x0043); 1356 + backup[14] = bcm43xx_radio_read16(bcm, 0x0051); 1357 + backup[15] = bcm43xx_radio_read16(bcm, 0x0052); 1358 + backup[1] = bcm43xx_phy_read(bcm, 0x0015); 1359 + backup[16] = bcm43xx_phy_read(bcm, 0x005A); 1360 + backup[17] = bcm43xx_phy_read(bcm, 0x0059); 1361 + backup[18] = bcm43xx_phy_read(bcm, 0x0058); 1362 + if (phy->type == BCM43xx_PHYTYPE_B) { 1363 + backup[2] = bcm43xx_phy_read(bcm, 0x0030); 1364 + backup[3] = bcm43xx_read16(bcm, 0x03EC); 1365 + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); 1366 + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); 1367 + } else { 1368 + if (phy->connected) { 1369 + backup[4] = bcm43xx_phy_read(bcm, 0x0811); 1370 + backup[5] = bcm43xx_phy_read(bcm, 0x0812); 1371 + backup[6] = bcm43xx_phy_read(bcm, 0x0814); 1372 + backup[7] = bcm43xx_phy_read(bcm, 0x0815); 1373 + backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); 1374 + backup[9] = bcm43xx_phy_read(bcm, 0x0802); 1375 + bcm43xx_phy_write(bcm, 0x0814, 1376 + (bcm43xx_phy_read(bcm, 0x0814) | 0x0003)); 1377 + bcm43xx_phy_write(bcm, 0x0815, 1378 + (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC)); 1379 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, 1380 + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF)); 1381 + bcm43xx_phy_write(bcm, 0x0802, 1382 + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); 1383 + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); 1384 + bcm43xx_phy_write(bcm, 0x0812, 0x0FB2); 1385 + } 1386 + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 1387 + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); 1388 + } 1389 + backup[10] = bcm43xx_phy_read(bcm, 0x0035); 1390 + bcm43xx_phy_write(bcm, 0x0035, 1391 + (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); 1392 + backup[11] = bcm43xx_read16(bcm, 0x03E6); 1393 + backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); 1394 + 1395 + // Initialization 1396 + if (phy->version == 0) { 1397 + bcm43xx_write16(bcm, 0x03E6, 0x0122); 1398 + } else { 1399 + if (phy->version >= 2) 1400 + bcm43xx_write16(bcm, 0x03E6, 0x0040); 1401 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 1402 + (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000)); 1403 + } 1404 + 1405 + ret = bcm43xx_radio_calibrationvalue(bcm); 1406 + 1407 + if (phy->type == BCM43xx_PHYTYPE_B) 1408 + bcm43xx_radio_write16(bcm, 0x0078, 0x0003); 1409 + 1410 + bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); 1411 + bcm43xx_phy_write(bcm, 0x002B, 0x1403); 1412 + if (phy->connected) 1413 + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); 1414 + bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); 1415 + bcm43xx_radio_write16(bcm, 0x0051, 1416 + (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); 1417 + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); 1418 + bcm43xx_radio_write16(bcm, 0x0043, 1419 + bcm43xx_radio_read16(bcm, 0x0043) | 0x0009); 1420 + bcm43xx_phy_write(bcm, 0x0058, 0x0000); 1421 + 1422 + for (i = 0; i < 16; i++) { 1423 + bcm43xx_phy_write(bcm, 0x005A, 0x0480); 1424 + bcm43xx_phy_write(bcm, 0x0059, 0xC810); 1425 + bcm43xx_phy_write(bcm, 0x0058, 0x000D); 1426 + if (phy->connected) 1427 + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); 1428 + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); 1429 + udelay(10); 1430 + if (phy->connected) 1431 + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); 1432 + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); 1433 + udelay(10); 1434 + if (phy->connected) 1435 + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); 1436 + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); 1437 + udelay(10); 1438 + tmp1 += bcm43xx_phy_read(bcm, 0x002D); 1439 + bcm43xx_phy_write(bcm, 0x0058, 0x0000); 1440 + if (phy->connected) 1441 + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); 1442 + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); 1443 + } 1444 + 1445 + tmp1++; 1446 + tmp1 >>= 9; 1447 + udelay(10); 1448 + bcm43xx_phy_write(bcm, 0x0058, 0x0000); 1449 + 1450 + for (i = 0; i < 16; i++) { 1451 + bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020); 1452 + backup[13] = bcm43xx_radio_read16(bcm, 0x0078); 1453 + udelay(10); 1454 + for (j = 0; j < 16; j++) { 1455 + bcm43xx_phy_write(bcm, 0x005A, 0x0D80); 1456 + bcm43xx_phy_write(bcm, 0x0059, 0xC810); 1457 + bcm43xx_phy_write(bcm, 0x0058, 0x000D); 1458 + if (phy->connected) 1459 + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); 1460 + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); 1461 + udelay(10); 1462 + if (phy->connected) 1463 + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); 1464 + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); 1465 + udelay(10); 1466 + if (phy->connected) 1467 + bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */ 1468 + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); 1469 + udelay(10); 1470 + tmp2 += bcm43xx_phy_read(bcm, 0x002D); 1471 + bcm43xx_phy_write(bcm, 0x0058, 0x0000); 1472 + if (phy->connected) 1473 + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); 1474 + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); 1475 + } 1476 + tmp2++; 1477 + tmp2 >>= 8; 1478 + if (tmp1 < tmp2) 1479 + break; 1480 + } 1481 + 1482 + /* Restore the registers */ 1483 + bcm43xx_phy_write(bcm, 0x0015, backup[1]); 1484 + bcm43xx_radio_write16(bcm, 0x0051, backup[14]); 1485 + bcm43xx_radio_write16(bcm, 0x0052, backup[15]); 1486 + bcm43xx_radio_write16(bcm, 0x0043, backup[0]); 1487 + bcm43xx_phy_write(bcm, 0x005A, backup[16]); 1488 + bcm43xx_phy_write(bcm, 0x0059, backup[17]); 1489 + bcm43xx_phy_write(bcm, 0x0058, backup[18]); 1490 + bcm43xx_write16(bcm, 0x03E6, backup[11]); 1491 + if (phy->version != 0) 1492 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]); 1493 + bcm43xx_phy_write(bcm, 0x0035, backup[10]); 1494 + bcm43xx_radio_selectchannel(bcm, radio->channel, 1); 1495 + if (phy->type == BCM43xx_PHYTYPE_B) { 1496 + bcm43xx_phy_write(bcm, 0x0030, backup[2]); 1497 + bcm43xx_write16(bcm, 0x03EC, backup[3]); 1498 + } else { 1499 + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 1500 + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); 1501 + if (phy->connected) { 1502 + bcm43xx_phy_write(bcm, 0x0811, backup[4]); 1503 + bcm43xx_phy_write(bcm, 0x0812, backup[5]); 1504 + bcm43xx_phy_write(bcm, 0x0814, backup[6]); 1505 + bcm43xx_phy_write(bcm, 0x0815, backup[7]); 1506 + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); 1507 + bcm43xx_phy_write(bcm, 0x0802, backup[9]); 1508 + } 1509 + } 1510 + if (i >= 15) 1511 + ret = backup[13]; 1512 + 1513 + return ret; 1514 + } 1515 + 1516 + void bcm43xx_radio_init2060(struct bcm43xx_private *bcm) 1517 + { 1518 + int err; 1519 + 1520 + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); 1521 + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); 1522 + bcm43xx_radio_write16(bcm, 0x0009, 0x0040); 1523 + bcm43xx_radio_write16(bcm, 0x0005, 0x00AA); 1524 + bcm43xx_radio_write16(bcm, 0x0032, 0x008F); 1525 + bcm43xx_radio_write16(bcm, 0x0006, 0x008F); 1526 + bcm43xx_radio_write16(bcm, 0x0034, 0x008F); 1527 + bcm43xx_radio_write16(bcm, 0x002C, 0x0007); 1528 + bcm43xx_radio_write16(bcm, 0x0082, 0x0080); 1529 + bcm43xx_radio_write16(bcm, 0x0080, 0x0000); 1530 + bcm43xx_radio_write16(bcm, 0x003F, 0x00DA); 1531 + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); 1532 + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010); 1533 + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); 1534 + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); 1535 + udelay(400); 1536 + 1537 + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010); 1538 + udelay(400); 1539 + 1540 + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008); 1541 + bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010); 1542 + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); 1543 + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040); 1544 + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040); 1545 + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008); 1546 + bcm43xx_phy_write(bcm, 0x0063, 0xDDC6); 1547 + bcm43xx_phy_write(bcm, 0x0069, 0x07BE); 1548 + bcm43xx_phy_write(bcm, 0x006A, 0x0000); 1549 + 1550 + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0); 1551 + assert(err == 0); 1552 + udelay(1000); 1553 + } 1554 + 1555 + static inline 1556 + u16 freq_r3A_value(u16 frequency) 1557 + { 1558 + u16 value; 1559 + 1560 + if (frequency < 5091) 1561 + value = 0x0040; 1562 + else if (frequency < 5321) 1563 + value = 0x0000; 1564 + else if (frequency < 5806) 1565 + value = 0x0080; 1566 + else 1567 + value = 0x0040; 1568 + 1569 + return value; 1570 + } 1571 + 1572 + void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm) 1573 + { 1574 + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; 1575 + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; 1576 + u16 tmp = bcm43xx_radio_read16(bcm, 0x001E); 1577 + int i, j; 1578 + 1579 + for (i = 0; i < 5; i++) { 1580 + for (j = 0; j < 5; j++) { 1581 + if (tmp == (data_high[i] << 4 | data_low[j])) { 1582 + bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0); 1583 + return; 1584 + } 1585 + } 1586 + } 1587 + } 1588 + 1589 + int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, 1590 + u8 channel, 1591 + int synthetic_pu_workaround) 1592 + { 1593 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1594 + u16 r8, tmp; 1595 + u16 freq; 1596 + 1597 + if ((radio->manufact == 0x17F) && 1598 + (radio->version == 0x2060) && 1599 + (radio->revision == 1)) { 1600 + if (channel > 200) 1601 + return -EINVAL; 1602 + freq = channel2freq_a(channel); 1603 + 1604 + r8 = bcm43xx_radio_read16(bcm, 0x0008); 1605 + bcm43xx_write16(bcm, 0x03F0, freq); 1606 + bcm43xx_radio_write16(bcm, 0x0008, r8); 1607 + 1608 + TODO();//TODO: write max channel TX power? to Radio 0x2D 1609 + tmp = bcm43xx_radio_read16(bcm, 0x002E); 1610 + tmp &= 0x0080; 1611 + TODO();//TODO: OR tmp with the Power out estimation for this channel? 1612 + bcm43xx_radio_write16(bcm, 0x002E, tmp); 1613 + 1614 + if (freq >= 4920 && freq <= 5500) { 1615 + /* 1616 + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; 1617 + * = (freq * 0.025862069 1618 + */ 1619 + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ 1620 + } 1621 + bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8); 1622 + bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8); 1623 + bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8); 1624 + bcm43xx_radio_write16(bcm, 0x0022, 1625 + (bcm43xx_radio_read16(bcm, 0x0022) 1626 + & 0x000F) | (r8 << 4)); 1627 + bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4)); 1628 + bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4)); 1629 + bcm43xx_radio_write16(bcm, 0x0008, 1630 + (bcm43xx_radio_read16(bcm, 0x0008) 1631 + & 0x00F0) | (r8 << 4)); 1632 + bcm43xx_radio_write16(bcm, 0x0029, 1633 + (bcm43xx_radio_read16(bcm, 0x0029) 1634 + & 0xFF0F) | 0x00B0); 1635 + bcm43xx_radio_write16(bcm, 0x0035, 0x00AA); 1636 + bcm43xx_radio_write16(bcm, 0x0036, 0x0085); 1637 + bcm43xx_radio_write16(bcm, 0x003A, 1638 + (bcm43xx_radio_read16(bcm, 0x003A) 1639 + & 0xFF20) | freq_r3A_value(freq)); 1640 + bcm43xx_radio_write16(bcm, 0x003D, 1641 + bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF); 1642 + bcm43xx_radio_write16(bcm, 0x0081, 1643 + (bcm43xx_radio_read16(bcm, 0x0081) 1644 + & 0xFF7F) | 0x0080); 1645 + bcm43xx_radio_write16(bcm, 0x0035, 1646 + bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF); 1647 + bcm43xx_radio_write16(bcm, 0x0035, 1648 + (bcm43xx_radio_read16(bcm, 0x0035) 1649 + & 0xFFEF) | 0x0010); 1650 + bcm43xx_radio_set_tx_iq(bcm); 1651 + TODO(); //TODO: TSSI2dbm workaround 1652 + bcm43xx_phy_xmitpower(bcm);//FIXME correct? 1653 + } else { 1654 + if ((channel < 1) || (channel > 14)) 1655 + return -EINVAL; 1656 + 1657 + if (synthetic_pu_workaround) 1658 + bcm43xx_synth_pu_workaround(bcm, channel); 1659 + 1660 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, 1661 + channel2freq_bg(channel)); 1662 + 1663 + if (channel == 14) { 1664 + if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) { 1665 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 1666 + BCM43xx_UCODEFLAGS_OFFSET, 1667 + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 1668 + BCM43xx_UCODEFLAGS_OFFSET) 1669 + & ~(1 << 7)); 1670 + } else { 1671 + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 1672 + BCM43xx_UCODEFLAGS_OFFSET, 1673 + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 1674 + BCM43xx_UCODEFLAGS_OFFSET) 1675 + | (1 << 7)); 1676 + } 1677 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 1678 + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) 1679 + | (1 << 11)); 1680 + } else { 1681 + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 1682 + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) 1683 + & 0xF7BF); 1684 + } 1685 + } 1686 + 1687 + radio->channel = channel; 1688 + //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states 1689 + // that 2000 usecs might suffice. 1690 + udelay(8000); 1691 + 1692 + return 0; 1693 + } 1694 + 1695 + void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val) 1696 + { 1697 + u16 tmp; 1698 + 1699 + val <<= 8; 1700 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF; 1701 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val); 1702 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF; 1703 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val); 1704 + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF; 1705 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val); 1706 + } 1707 + 1708 + /* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ 1709 + static u16 bcm43xx_get_txgain_base_band(u16 txpower) 1710 + { 1711 + u16 ret; 1712 + 1713 + assert(txpower <= 63); 1714 + 1715 + if (txpower >= 54) 1716 + ret = 2; 1717 + else if (txpower >= 49) 1718 + ret = 4; 1719 + else if (txpower >= 44) 1720 + ret = 5; 1721 + else 1722 + ret = 6; 1723 + 1724 + return ret; 1725 + } 1726 + 1727 + /* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ 1728 + static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower) 1729 + { 1730 + u16 ret; 1731 + 1732 + assert(txpower <= 63); 1733 + 1734 + if (txpower >= 32) 1735 + ret = 0; 1736 + else if (txpower >= 25) 1737 + ret = 1; 1738 + else if (txpower >= 20) 1739 + ret = 2; 1740 + else if (txpower >= 12) 1741 + ret = 3; 1742 + else 1743 + ret = 4; 1744 + 1745 + return ret; 1746 + } 1747 + 1748 + /* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ 1749 + static u16 bcm43xx_get_txgain_dac(u16 txpower) 1750 + { 1751 + u16 ret; 1752 + 1753 + assert(txpower <= 63); 1754 + 1755 + if (txpower >= 54) 1756 + ret = txpower - 53; 1757 + else if (txpower >= 49) 1758 + ret = txpower - 42; 1759 + else if (txpower >= 44) 1760 + ret = txpower - 37; 1761 + else if (txpower >= 32) 1762 + ret = txpower - 32; 1763 + else if (txpower >= 25) 1764 + ret = txpower - 20; 1765 + else if (txpower >= 20) 1766 + ret = txpower - 13; 1767 + else if (txpower >= 12) 1768 + ret = txpower - 8; 1769 + else 1770 + ret = txpower; 1771 + 1772 + return ret; 1773 + } 1774 + 1775 + void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) 1776 + { 1777 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1778 + u16 pamp, base, dac, ilt; 1779 + 1780 + txpower = limit_value(txpower, 0, 63); 1781 + 1782 + pamp = bcm43xx_get_txgain_freq_power_amp(txpower); 1783 + pamp <<= 5; 1784 + pamp &= 0x00E0; 1785 + bcm43xx_phy_write(bcm, 0x0019, pamp); 1786 + 1787 + base = bcm43xx_get_txgain_base_band(txpower); 1788 + base &= 0x000F; 1789 + bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); 1790 + 1791 + ilt = bcm43xx_ilt_read(bcm, 0x3001); 1792 + ilt &= 0x0007; 1793 + 1794 + dac = bcm43xx_get_txgain_dac(txpower); 1795 + dac <<= 3; 1796 + dac |= ilt; 1797 + 1798 + bcm43xx_ilt_write(bcm, 0x3001, dac); 1799 + 1800 + radio->txpwr_offset = txpower; 1801 + 1802 + TODO(); 1803 + //TODO: FuncPlaceholder (Adjust BB loft cancel) 1804 + } 1805 + 1806 + void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, 1807 + u16 baseband_attenuation, u16 radio_attenuation, 1808 + u16 txpower) 1809 + { 1810 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1811 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1812 + 1813 + if (baseband_attenuation == 0xFFFF) 1814 + baseband_attenuation = radio->baseband_atten; 1815 + if (radio_attenuation == 0xFFFF) 1816 + radio_attenuation = radio->radio_atten; 1817 + if (txpower == 0xFFFF) 1818 + txpower = radio->txctl1; 1819 + radio->baseband_atten = baseband_attenuation; 1820 + radio->radio_atten = radio_attenuation; 1821 + radio->txctl1 = txpower; 1822 + 1823 + assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); 1824 + if (radio->revision < 6) 1825 + assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9); 1826 + else 1827 + assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31); 1828 + assert(/*txpower >= 0 &&*/ txpower <= 7); 1829 + 1830 + bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation); 1831 + bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation); 1832 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); 1833 + if (radio->version == 0x2050) { 1834 + bcm43xx_radio_write16(bcm, 0x0052, 1835 + (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) 1836 + | ((txpower << 4) & 0x0070)); 1837 + } 1838 + //FIXME: The spec is very weird and unclear here. 1839 + if (phy->type == BCM43xx_PHYTYPE_G) 1840 + bcm43xx_phy_lo_adjust(bcm, 0); 1841 + } 1842 + 1843 + u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm) 1844 + { 1845 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1846 + 1847 + if (radio->version == 0x2050 && radio->revision < 6) 1848 + return 0; 1849 + return 2; 1850 + } 1851 + 1852 + u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm) 1853 + { 1854 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1855 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1856 + u16 att = 0xFFFF; 1857 + 1858 + if (phy->type == BCM43xx_PHYTYPE_A) 1859 + return 0x60; 1860 + 1861 + switch (radio->version) { 1862 + case 0x2053: 1863 + switch (radio->revision) { 1864 + case 1: 1865 + att = 6; 1866 + break; 1867 + } 1868 + break; 1869 + case 0x2050: 1870 + switch (radio->revision) { 1871 + case 0: 1872 + att = 5; 1873 + break; 1874 + case 1: 1875 + if (phy->type == BCM43xx_PHYTYPE_G) { 1876 + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && 1877 + bcm->board_type == 0x421 && 1878 + bcm->board_revision >= 30) 1879 + att = 3; 1880 + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && 1881 + bcm->board_type == 0x416) 1882 + att = 3; 1883 + else 1884 + att = 1; 1885 + } else { 1886 + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && 1887 + bcm->board_type == 0x421 && 1888 + bcm->board_revision >= 30) 1889 + att = 7; 1890 + else 1891 + att = 6; 1892 + } 1893 + break; 1894 + case 2: 1895 + if (phy->type == BCM43xx_PHYTYPE_G) { 1896 + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && 1897 + bcm->board_type == 0x421 && 1898 + bcm->board_revision >= 30) 1899 + att = 3; 1900 + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && 1901 + bcm->board_type == 0x416) 1902 + att = 5; 1903 + else if (bcm->chip_id == 0x4320) 1904 + att = 4; 1905 + else 1906 + att = 3; 1907 + } else 1908 + att = 6; 1909 + break; 1910 + case 3: 1911 + att = 5; 1912 + break; 1913 + case 4: 1914 + case 5: 1915 + att = 1; 1916 + break; 1917 + case 6: 1918 + case 7: 1919 + att = 5; 1920 + break; 1921 + case 8: 1922 + att = 0x1A; 1923 + break; 1924 + case 9: 1925 + default: 1926 + att = 5; 1927 + } 1928 + } 1929 + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && 1930 + bcm->board_type == 0x421) { 1931 + if (bcm->board_revision < 0x43) 1932 + att = 2; 1933 + else if (bcm->board_revision < 0x51) 1934 + att = 3; 1935 + } 1936 + if (att == 0xFFFF) 1937 + att = 5; 1938 + 1939 + return att; 1940 + } 1941 + 1942 + u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm) 1943 + { 1944 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1945 + 1946 + if (radio->version != 0x2050) 1947 + return 0; 1948 + if (radio->revision == 1) 1949 + return 3; 1950 + if (radio->revision < 6) 1951 + return 2; 1952 + if (radio->revision == 8) 1953 + return 1; 1954 + return 0; 1955 + } 1956 + 1957 + void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) 1958 + { 1959 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1960 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1961 + int err; 1962 + 1963 + if (radio->enabled) 1964 + return; 1965 + 1966 + switch (phy->type) { 1967 + case BCM43xx_PHYTYPE_A: 1968 + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); 1969 + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); 1970 + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7); 1971 + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7); 1972 + bcm43xx_radio_init2060(bcm); 1973 + break; 1974 + case BCM43xx_PHYTYPE_B: 1975 + case BCM43xx_PHYTYPE_G: 1976 + bcm43xx_phy_write(bcm, 0x0015, 0x8000); 1977 + bcm43xx_phy_write(bcm, 0x0015, 0xCC00); 1978 + bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000)); 1979 + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1); 1980 + assert(err == 0); 1981 + break; 1982 + default: 1983 + assert(0); 1984 + } 1985 + radio->enabled = 1; 1986 + dprintk(KERN_INFO PFX "Radio turned on\n"); 1987 + } 1988 + 1989 + void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) 1990 + { 1991 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 1992 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 1993 + 1994 + if (phy->type == BCM43xx_PHYTYPE_A) { 1995 + bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); 1996 + bcm43xx_radio_write16(bcm, 0x0005, 0x00FB); 1997 + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008); 1998 + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008); 1999 + } 2000 + if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) { 2001 + bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C); 2002 + bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73); 2003 + } else 2004 + bcm43xx_phy_write(bcm, 0x0015, 0xAA00); 2005 + radio->enabled = 0; 2006 + dprintk(KERN_INFO PFX "Radio turned off\n"); 2007 + } 2008 + 2009 + void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) 2010 + { 2011 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2012 + 2013 + switch (phy->type) { 2014 + case BCM43xx_PHYTYPE_A: 2015 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); 2016 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); 2017 + break; 2018 + case BCM43xx_PHYTYPE_B: 2019 + case BCM43xx_PHYTYPE_G: 2020 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F); 2021 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F); 2022 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F); 2023 + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F); 2024 + break; 2025 + } 2026 + }
+99
drivers/net/wireless/bcm43xx/bcm43xx_radio.h
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #ifndef BCM43xx_RADIO_H_ 32 + #define BCM43xx_RADIO_H_ 33 + 34 + #include "bcm43xx.h" 35 + 36 + 37 + #define BCM43xx_RADIO_DEFAULT_CHANNEL_A 36 38 + #define BCM43xx_RADIO_DEFAULT_CHANNEL_BG 6 39 + 40 + /* Force antenna 0. */ 41 + #define BCM43xx_RADIO_TXANTENNA_0 0 42 + /* Force antenna 1. */ 43 + #define BCM43xx_RADIO_TXANTENNA_1 1 44 + /* Use the RX antenna, that was selected for the most recently 45 + * received good PLCP header. 46 + */ 47 + #define BCM43xx_RADIO_TXANTENNA_LASTPLCP 3 48 + #define BCM43xx_RADIO_TXANTENNA_DEFAULT BCM43xx_RADIO_TXANTENNA_LASTPLCP 49 + 50 + #define BCM43xx_RADIO_INTERFMODE_NONE 0 51 + #define BCM43xx_RADIO_INTERFMODE_NONWLAN 1 52 + #define BCM43xx_RADIO_INTERFMODE_MANUALWLAN 2 53 + #define BCM43xx_RADIO_INTERFMODE_AUTOWLAN 3 54 + 55 + 56 + void bcm43xx_radio_lock(struct bcm43xx_private *bcm); 57 + void bcm43xx_radio_unlock(struct bcm43xx_private *bcm); 58 + 59 + u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset); 60 + void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); 61 + 62 + u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm); 63 + void bcm43xx_radio_init2060(struct bcm43xx_private *bcm); 64 + 65 + void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm); 66 + void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm); 67 + 68 + int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, 69 + int synthetic_pu_workaround); 70 + 71 + void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower); 72 + void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, 73 + u16 baseband_attenuation, u16 attenuation, 74 + u16 txpower); 75 + 76 + u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm); 77 + u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm); 78 + u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm); 79 + 80 + void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val); 81 + 82 + void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm); 83 + 84 + u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel); 85 + u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm); 86 + 87 + int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode); 88 + 89 + void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm); 90 + void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm); 91 + s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset); 92 + void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val); 93 + void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val); 94 + void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm); 95 + 96 + void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm); 97 + u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm); 98 + 99 + #endif /* BCM43xx_RADIO_H_ */
+322
drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + SYSFS support routines 6 + 7 + Copyright (c) 2006 Michael Buesch <mbuesch@freenet.de> 8 + 9 + This program is free software; you can redistribute it and/or modify 10 + it under the terms of the GNU General Public License as published by 11 + the Free Software Foundation; either version 2 of the License, or 12 + (at your option) any later version. 13 + 14 + This program is distributed in the hope that it will be useful, 15 + but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + GNU General Public License for more details. 18 + 19 + You should have received a copy of the GNU General Public License 20 + along with this program; see the file COPYING. If not, write to 21 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 22 + Boston, MA 02110-1301, USA. 23 + 24 + */ 25 + 26 + #include "bcm43xx_sysfs.h" 27 + #include "bcm43xx.h" 28 + #include "bcm43xx_main.h" 29 + #include "bcm43xx_radio.h" 30 + 31 + #include <linux/capability.h> 32 + 33 + 34 + #define GENERIC_FILESIZE 64 35 + 36 + 37 + static int get_integer(const char *buf, size_t count) 38 + { 39 + char tmp[10 + 1] = { 0 }; 40 + int ret = -EINVAL; 41 + 42 + if (count == 0) 43 + goto out; 44 + count = min(count, (size_t)10); 45 + memcpy(tmp, buf, count); 46 + ret = simple_strtol(tmp, NULL, 10); 47 + out: 48 + return ret; 49 + } 50 + 51 + static int get_boolean(const char *buf, size_t count) 52 + { 53 + if (count != 0) { 54 + if (buf[0] == '1') 55 + return 1; 56 + if (buf[0] == '0') 57 + return 0; 58 + if (count >= 4 && memcmp(buf, "true", 4) == 0) 59 + return 1; 60 + if (count >= 5 && memcmp(buf, "false", 5) == 0) 61 + return 0; 62 + if (count >= 3 && memcmp(buf, "yes", 3) == 0) 63 + return 1; 64 + if (count >= 2 && memcmp(buf, "no", 2) == 0) 65 + return 0; 66 + if (count >= 2 && memcmp(buf, "on", 2) == 0) 67 + return 1; 68 + if (count >= 3 && memcmp(buf, "off", 3) == 0) 69 + return 0; 70 + } 71 + return -EINVAL; 72 + } 73 + 74 + static ssize_t bcm43xx_attr_sprom_show(struct device *dev, 75 + struct device_attribute *attr, 76 + char *buf) 77 + { 78 + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); 79 + u16 *sprom; 80 + unsigned long flags; 81 + int i, err; 82 + 83 + if (!capable(CAP_NET_ADMIN)) 84 + return -EPERM; 85 + 86 + assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE); 87 + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), 88 + GFP_KERNEL); 89 + if (!sprom) 90 + return -ENOMEM; 91 + bcm43xx_lock_mmio(bcm, flags); 92 + assert(bcm->initialized); 93 + err = bcm43xx_sprom_read(bcm, sprom); 94 + if (!err) { 95 + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { 96 + buf[i * 2] = sprom[i] & 0x00FF; 97 + buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; 98 + } 99 + } 100 + bcm43xx_unlock_mmio(bcm, flags); 101 + kfree(sprom); 102 + 103 + return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); 104 + } 105 + 106 + static ssize_t bcm43xx_attr_sprom_store(struct device *dev, 107 + struct device_attribute *attr, 108 + const char *buf, size_t count) 109 + { 110 + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); 111 + u16 *sprom; 112 + unsigned long flags; 113 + int i, err; 114 + 115 + if (!capable(CAP_NET_ADMIN)) 116 + return -EPERM; 117 + 118 + if (count != BCM43xx_SPROM_SIZE * sizeof(u16)) 119 + return -EINVAL; 120 + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), 121 + GFP_KERNEL); 122 + if (!sprom) 123 + return -ENOMEM; 124 + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { 125 + sprom[i] = buf[i * 2] & 0xFF; 126 + sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; 127 + } 128 + bcm43xx_lock_mmio(bcm, flags); 129 + assert(bcm->initialized); 130 + err = bcm43xx_sprom_write(bcm, sprom); 131 + bcm43xx_unlock_mmio(bcm, flags); 132 + kfree(sprom); 133 + 134 + return err ? err : count; 135 + 136 + } 137 + 138 + static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, 139 + struct device_attribute *attr, 140 + char *buf) 141 + { 142 + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); 143 + unsigned long flags; 144 + int err; 145 + ssize_t count = 0; 146 + 147 + if (!capable(CAP_NET_ADMIN)) 148 + return -EPERM; 149 + 150 + bcm43xx_lock(bcm, flags); 151 + assert(bcm->initialized); 152 + 153 + switch (bcm43xx_current_radio(bcm)->interfmode) { 154 + case BCM43xx_RADIO_INTERFMODE_NONE: 155 + count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n"); 156 + break; 157 + case BCM43xx_RADIO_INTERFMODE_NONWLAN: 158 + count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n"); 159 + break; 160 + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: 161 + count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n"); 162 + break; 163 + default: 164 + assert(0); 165 + } 166 + err = 0; 167 + 168 + bcm43xx_unlock(bcm, flags); 169 + 170 + return err ? err : count; 171 + 172 + } 173 + 174 + static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, 175 + struct device_attribute *attr, 176 + const char *buf, size_t count) 177 + { 178 + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); 179 + unsigned long flags; 180 + int err; 181 + int mode; 182 + 183 + if (!capable(CAP_NET_ADMIN)) 184 + return -EPERM; 185 + 186 + mode = get_integer(buf, count); 187 + switch (mode) { 188 + case 0: 189 + mode = BCM43xx_RADIO_INTERFMODE_NONE; 190 + break; 191 + case 1: 192 + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; 193 + break; 194 + case 2: 195 + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; 196 + break; 197 + case 3: 198 + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; 199 + break; 200 + default: 201 + return -EINVAL; 202 + } 203 + 204 + bcm43xx_lock_mmio(bcm, flags); 205 + assert(bcm->initialized); 206 + 207 + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); 208 + if (err) { 209 + printk(KERN_ERR PFX "Interference Mitigation not " 210 + "supported by device\n"); 211 + } 212 + 213 + bcm43xx_unlock_mmio(bcm, flags); 214 + 215 + return err ? err : count; 216 + } 217 + 218 + static ssize_t bcm43xx_attr_preamble_show(struct device *dev, 219 + struct device_attribute *attr, 220 + char *buf) 221 + { 222 + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); 223 + unsigned long flags; 224 + int err; 225 + ssize_t count; 226 + 227 + if (!capable(CAP_NET_ADMIN)) 228 + return -EPERM; 229 + 230 + bcm43xx_lock(bcm, flags); 231 + assert(bcm->initialized); 232 + 233 + if (bcm->short_preamble) 234 + count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); 235 + else 236 + count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); 237 + 238 + err = 0; 239 + bcm43xx_unlock(bcm, flags); 240 + 241 + return err ? err : count; 242 + } 243 + 244 + static ssize_t bcm43xx_attr_preamble_store(struct device *dev, 245 + struct device_attribute *attr, 246 + const char *buf, size_t count) 247 + { 248 + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); 249 + unsigned long flags; 250 + int err; 251 + int value; 252 + 253 + if (!capable(CAP_NET_ADMIN)) 254 + return -EPERM; 255 + 256 + value = get_boolean(buf, count); 257 + if (value < 0) 258 + return value; 259 + bcm43xx_lock(bcm, flags); 260 + assert(bcm->initialized); 261 + 262 + bcm->short_preamble = !!value; 263 + 264 + err = 0; 265 + bcm43xx_unlock(bcm, flags); 266 + 267 + return err ? err : count; 268 + } 269 + 270 + int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) 271 + { 272 + struct device *dev = &bcm->pci_dev->dev; 273 + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; 274 + int err; 275 + 276 + assert(bcm->initialized); 277 + 278 + sysfs->attr_sprom.attr.name = "sprom"; 279 + sysfs->attr_sprom.attr.owner = THIS_MODULE; 280 + sysfs->attr_sprom.attr.mode = 0600; 281 + sysfs->attr_sprom.show = bcm43xx_attr_sprom_show; 282 + sysfs->attr_sprom.store = bcm43xx_attr_sprom_store; 283 + err = device_create_file(dev, &sysfs->attr_sprom); 284 + if (err) 285 + goto out; 286 + 287 + sysfs->attr_interfmode.attr.name = "interference"; 288 + sysfs->attr_interfmode.attr.owner = THIS_MODULE; 289 + sysfs->attr_interfmode.attr.mode = 0600; 290 + sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show; 291 + sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store; 292 + err = device_create_file(dev, &sysfs->attr_interfmode); 293 + if (err) 294 + goto err_remove_sprom; 295 + 296 + sysfs->attr_preamble.attr.name = "shortpreamble"; 297 + sysfs->attr_preamble.attr.owner = THIS_MODULE; 298 + sysfs->attr_preamble.attr.mode = 0600; 299 + sysfs->attr_preamble.show = bcm43xx_attr_preamble_show; 300 + sysfs->attr_preamble.store = bcm43xx_attr_preamble_store; 301 + err = device_create_file(dev, &sysfs->attr_preamble); 302 + if (err) 303 + goto err_remove_interfmode; 304 + 305 + out: 306 + return err; 307 + err_remove_interfmode: 308 + device_remove_file(dev, &sysfs->attr_interfmode); 309 + err_remove_sprom: 310 + device_remove_file(dev, &sysfs->attr_sprom); 311 + goto out; 312 + } 313 + 314 + void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) 315 + { 316 + struct device *dev = &bcm->pci_dev->dev; 317 + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; 318 + 319 + device_remove_file(dev, &sysfs->attr_preamble); 320 + device_remove_file(dev, &sysfs->attr_interfmode); 321 + device_remove_file(dev, &sysfs->attr_sprom); 322 + }
+25
drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h
··· 1 + #ifndef BCM43xx_SYSFS_H_ 2 + #define BCM43xx_SYSFS_H_ 3 + 4 + #include <linux/device.h> 5 + 6 + 7 + struct bcm43xx_sysfs { 8 + struct device_attribute attr_sprom; 9 + struct device_attribute attr_interfmode; 10 + struct device_attribute attr_preamble; 11 + }; 12 + 13 + #define devattr_to_bcm(attr, attr_name) ({ \ 14 + struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \ 15 + __s = container_of((attr), struct bcm43xx_sysfs, attr_name); \ 16 + __p = container_of(__s, struct bcm43xx_private, sysfs); \ 17 + __p; \ 18 + }) 19 + 20 + struct bcm43xx_private; 21 + 22 + int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); 23 + void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm); 24 + 25 + #endif /* BCM43xx_SYSFS_H_ */
+1002
drivers/net/wireless/bcm43xx/bcm43xx_wx.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #include <linux/wireless.h> 32 + #include <net/iw_handler.h> 33 + #include <net/ieee80211softmac.h> 34 + #include <net/ieee80211softmac_wx.h> 35 + #include <linux/capability.h> 36 + #include <linux/sched.h> /* for capable() */ 37 + #include <linux/delay.h> 38 + 39 + #include "bcm43xx.h" 40 + #include "bcm43xx_wx.h" 41 + #include "bcm43xx_main.h" 42 + #include "bcm43xx_radio.h" 43 + #include "bcm43xx_phy.h" 44 + 45 + 46 + /* The WIRELESS_EXT version, which is implemented by this driver. */ 47 + #define BCM43xx_WX_VERSION 18 48 + 49 + #define MAX_WX_STRING 80 50 + 51 + 52 + static int bcm43xx_wx_get_name(struct net_device *net_dev, 53 + struct iw_request_info *info, 54 + union iwreq_data *data, 55 + char *extra) 56 + { 57 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 58 + unsigned long flags; 59 + int i; 60 + struct bcm43xx_phyinfo *phy; 61 + char suffix[7] = { 0 }; 62 + int have_a = 0, have_b = 0, have_g = 0; 63 + 64 + bcm43xx_lock(bcm, flags); 65 + for (i = 0; i < bcm->nr_80211_available; i++) { 66 + phy = &(bcm->core_80211_ext[i].phy); 67 + switch (phy->type) { 68 + case BCM43xx_PHYTYPE_A: 69 + have_a = 1; 70 + break; 71 + case BCM43xx_PHYTYPE_G: 72 + have_g = 1; 73 + case BCM43xx_PHYTYPE_B: 74 + have_b = 1; 75 + break; 76 + default: 77 + assert(0); 78 + } 79 + } 80 + bcm43xx_unlock(bcm, flags); 81 + 82 + i = 0; 83 + if (have_a) { 84 + suffix[i++] = 'a'; 85 + suffix[i++] = '/'; 86 + } 87 + if (have_b) { 88 + suffix[i++] = 'b'; 89 + suffix[i++] = '/'; 90 + } 91 + if (have_g) { 92 + suffix[i++] = 'g'; 93 + suffix[i++] = '/'; 94 + } 95 + if (i != 0) 96 + suffix[i - 1] = '\0'; 97 + 98 + snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix); 99 + 100 + return 0; 101 + } 102 + 103 + static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, 104 + struct iw_request_info *info, 105 + union iwreq_data *data, 106 + char *extra) 107 + { 108 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 109 + unsigned long flags; 110 + u8 channel; 111 + int freq; 112 + int err = -EINVAL; 113 + 114 + bcm43xx_lock_mmio(bcm, flags); 115 + if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { 116 + channel = data->freq.m; 117 + freq = bcm43xx_channel_to_freq(bcm, channel); 118 + } else { 119 + channel = bcm43xx_freq_to_channel(bcm, data->freq.m); 120 + freq = data->freq.m; 121 + } 122 + if (!bcm43xx_is_valid_channel(bcm, channel)) 123 + goto out_unlock; 124 + if (bcm->initialized) { 125 + //ieee80211softmac_disassoc(softmac, $REASON); 126 + bcm43xx_mac_suspend(bcm); 127 + err = bcm43xx_radio_selectchannel(bcm, channel, 0); 128 + bcm43xx_mac_enable(bcm); 129 + } else { 130 + bcm43xx_current_radio(bcm)->initial_channel = channel; 131 + err = 0; 132 + } 133 + out_unlock: 134 + bcm43xx_unlock_mmio(bcm, flags); 135 + 136 + return err; 137 + } 138 + 139 + static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, 140 + struct iw_request_info *info, 141 + union iwreq_data *data, 142 + char *extra) 143 + { 144 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 145 + struct bcm43xx_radioinfo *radio; 146 + unsigned long flags; 147 + int err = -ENODEV; 148 + u16 channel; 149 + 150 + bcm43xx_lock(bcm, flags); 151 + radio = bcm43xx_current_radio(bcm); 152 + channel = radio->channel; 153 + if (channel == 0xFF) { 154 + assert(!bcm->initialized); 155 + channel = radio->initial_channel; 156 + if (channel == 0xFF) 157 + goto out_unlock; 158 + } 159 + assert(channel > 0 && channel <= 1000); 160 + data->freq.e = 1; 161 + data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000; 162 + data->freq.flags = 1; 163 + 164 + err = 0; 165 + out_unlock: 166 + bcm43xx_unlock(bcm, flags); 167 + 168 + return err; 169 + } 170 + 171 + static int bcm43xx_wx_set_mode(struct net_device *net_dev, 172 + struct iw_request_info *info, 173 + union iwreq_data *data, 174 + char *extra) 175 + { 176 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 177 + unsigned long flags; 178 + int mode; 179 + 180 + mode = data->mode; 181 + if (mode == IW_MODE_AUTO) 182 + mode = BCM43xx_INITIAL_IWMODE; 183 + 184 + bcm43xx_lock_mmio(bcm, flags); 185 + if (bcm->ieee->iw_mode != mode) 186 + bcm43xx_set_iwmode(bcm, mode); 187 + bcm43xx_unlock_mmio(bcm, flags); 188 + 189 + return 0; 190 + } 191 + 192 + static int bcm43xx_wx_get_mode(struct net_device *net_dev, 193 + struct iw_request_info *info, 194 + union iwreq_data *data, 195 + char *extra) 196 + { 197 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 198 + unsigned long flags; 199 + 200 + bcm43xx_lock(bcm, flags); 201 + data->mode = bcm->ieee->iw_mode; 202 + bcm43xx_unlock(bcm, flags); 203 + 204 + return 0; 205 + } 206 + 207 + static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, 208 + struct iw_request_info *info, 209 + union iwreq_data *data, 210 + char *extra) 211 + { 212 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 213 + struct iw_range *range = (struct iw_range *)extra; 214 + const struct ieee80211_geo *geo; 215 + unsigned long flags; 216 + int i, j; 217 + struct bcm43xx_phyinfo *phy; 218 + 219 + data->data.length = sizeof(*range); 220 + memset(range, 0, sizeof(*range)); 221 + 222 + //TODO: What about 802.11b? 223 + /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */ 224 + range->throughput = 27 * 1000 * 1000; 225 + 226 + range->max_qual.qual = 100; 227 + /* TODO: Real max RSSI */ 228 + range->max_qual.level = 3; 229 + range->max_qual.noise = 100; 230 + range->max_qual.updated = 7; 231 + 232 + range->avg_qual.qual = 70; 233 + range->avg_qual.level = 2; 234 + range->avg_qual.noise = 40; 235 + range->avg_qual.updated = 7; 236 + 237 + range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; 238 + range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; 239 + range->min_frag = MIN_FRAG_THRESHOLD; 240 + range->max_frag = MAX_FRAG_THRESHOLD; 241 + 242 + range->encoding_size[0] = 5; 243 + range->encoding_size[1] = 13; 244 + range->num_encoding_sizes = 2; 245 + range->max_encoding_tokens = WEP_KEYS; 246 + 247 + range->we_version_compiled = WIRELESS_EXT; 248 + range->we_version_source = BCM43xx_WX_VERSION; 249 + 250 + range->enc_capa = IW_ENC_CAPA_WPA | 251 + IW_ENC_CAPA_WPA2 | 252 + IW_ENC_CAPA_CIPHER_TKIP | 253 + IW_ENC_CAPA_CIPHER_CCMP; 254 + 255 + bcm43xx_lock(bcm, flags); 256 + phy = bcm43xx_current_phy(bcm); 257 + 258 + range->num_bitrates = 0; 259 + i = 0; 260 + if (phy->type == BCM43xx_PHYTYPE_A || 261 + phy->type == BCM43xx_PHYTYPE_G) { 262 + range->num_bitrates = 8; 263 + range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; 264 + range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; 265 + range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB; 266 + range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB; 267 + range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB; 268 + range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB; 269 + range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; 270 + range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; 271 + } 272 + if (phy->type == BCM43xx_PHYTYPE_B || 273 + phy->type == BCM43xx_PHYTYPE_G) { 274 + range->num_bitrates += 4; 275 + range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; 276 + range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; 277 + range->bitrate[i++] = IEEE80211_CCK_RATE_5MB; 278 + range->bitrate[i++] = IEEE80211_CCK_RATE_11MB; 279 + } 280 + 281 + geo = ieee80211_get_geo(bcm->ieee); 282 + range->num_channels = geo->a_channels + geo->bg_channels; 283 + j = 0; 284 + for (i = 0; i < geo->a_channels; i++) { 285 + if (j == IW_MAX_FREQUENCIES) 286 + break; 287 + range->freq[j].i = j + 1; 288 + range->freq[j].m = geo->a[i].freq;//FIXME? 289 + range->freq[j].e = 1; 290 + j++; 291 + } 292 + for (i = 0; i < geo->bg_channels; i++) { 293 + if (j == IW_MAX_FREQUENCIES) 294 + break; 295 + range->freq[j].i = j + 1; 296 + range->freq[j].m = geo->bg[i].freq;//FIXME? 297 + range->freq[j].e = 1; 298 + j++; 299 + } 300 + range->num_frequency = j; 301 + 302 + bcm43xx_unlock(bcm, flags); 303 + 304 + return 0; 305 + } 306 + 307 + static int bcm43xx_wx_set_nick(struct net_device *net_dev, 308 + struct iw_request_info *info, 309 + union iwreq_data *data, 310 + char *extra) 311 + { 312 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 313 + unsigned long flags; 314 + size_t len; 315 + 316 + bcm43xx_lock(bcm, flags); 317 + len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); 318 + memcpy(bcm->nick, extra, len); 319 + bcm->nick[len] = '\0'; 320 + bcm43xx_unlock(bcm, flags); 321 + 322 + return 0; 323 + } 324 + 325 + static int bcm43xx_wx_get_nick(struct net_device *net_dev, 326 + struct iw_request_info *info, 327 + union iwreq_data *data, 328 + char *extra) 329 + { 330 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 331 + unsigned long flags; 332 + size_t len; 333 + 334 + bcm43xx_lock(bcm, flags); 335 + len = strlen(bcm->nick) + 1; 336 + memcpy(extra, bcm->nick, len); 337 + data->data.length = (__u16)len; 338 + data->data.flags = 1; 339 + bcm43xx_unlock(bcm, flags); 340 + 341 + return 0; 342 + } 343 + 344 + static int bcm43xx_wx_set_rts(struct net_device *net_dev, 345 + struct iw_request_info *info, 346 + union iwreq_data *data, 347 + char *extra) 348 + { 349 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 350 + unsigned long flags; 351 + int err = -EINVAL; 352 + 353 + bcm43xx_lock(bcm, flags); 354 + if (data->rts.disabled) { 355 + bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; 356 + err = 0; 357 + } else { 358 + if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD && 359 + data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) { 360 + bcm->rts_threshold = data->rts.value; 361 + err = 0; 362 + } 363 + } 364 + bcm43xx_unlock(bcm, flags); 365 + 366 + return err; 367 + } 368 + 369 + static int bcm43xx_wx_get_rts(struct net_device *net_dev, 370 + struct iw_request_info *info, 371 + union iwreq_data *data, 372 + char *extra) 373 + { 374 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 375 + unsigned long flags; 376 + 377 + bcm43xx_lock(bcm, flags); 378 + data->rts.value = bcm->rts_threshold; 379 + data->rts.fixed = 0; 380 + data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); 381 + bcm43xx_unlock(bcm, flags); 382 + 383 + return 0; 384 + } 385 + 386 + static int bcm43xx_wx_set_frag(struct net_device *net_dev, 387 + struct iw_request_info *info, 388 + union iwreq_data *data, 389 + char *extra) 390 + { 391 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 392 + unsigned long flags; 393 + int err = -EINVAL; 394 + 395 + bcm43xx_lock(bcm, flags); 396 + if (data->frag.disabled) { 397 + bcm->ieee->fts = MAX_FRAG_THRESHOLD; 398 + err = 0; 399 + } else { 400 + if (data->frag.value >= MIN_FRAG_THRESHOLD && 401 + data->frag.value <= MAX_FRAG_THRESHOLD) { 402 + bcm->ieee->fts = data->frag.value & ~0x1; 403 + err = 0; 404 + } 405 + } 406 + bcm43xx_unlock(bcm, flags); 407 + 408 + return err; 409 + } 410 + 411 + static int bcm43xx_wx_get_frag(struct net_device *net_dev, 412 + struct iw_request_info *info, 413 + union iwreq_data *data, 414 + char *extra) 415 + { 416 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 417 + unsigned long flags; 418 + 419 + bcm43xx_lock(bcm, flags); 420 + data->frag.value = bcm->ieee->fts; 421 + data->frag.fixed = 0; 422 + data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); 423 + bcm43xx_unlock(bcm, flags); 424 + 425 + return 0; 426 + } 427 + 428 + static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, 429 + struct iw_request_info *info, 430 + union iwreq_data *data, 431 + char *extra) 432 + { 433 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 434 + struct bcm43xx_radioinfo *radio; 435 + struct bcm43xx_phyinfo *phy; 436 + unsigned long flags; 437 + int err = -ENODEV; 438 + u16 maxpower; 439 + 440 + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { 441 + printk(PFX KERN_ERR "TX power not in dBm.\n"); 442 + return -EOPNOTSUPP; 443 + } 444 + 445 + bcm43xx_lock_mmio(bcm, flags); 446 + if (!bcm->initialized) 447 + goto out_unlock; 448 + radio = bcm43xx_current_radio(bcm); 449 + phy = bcm43xx_current_phy(bcm); 450 + if (data->txpower.disabled != (!(radio->enabled))) { 451 + if (data->txpower.disabled) 452 + bcm43xx_radio_turn_off(bcm); 453 + else 454 + bcm43xx_radio_turn_on(bcm); 455 + } 456 + if (data->txpower.value > 0) { 457 + /* desired and maxpower dBm values are in Q5.2 */ 458 + if (phy->type == BCM43xx_PHYTYPE_A) 459 + maxpower = bcm->sprom.maxpower_aphy; 460 + else 461 + maxpower = bcm->sprom.maxpower_bgphy; 462 + radio->txpower_desired = limit_value(data->txpower.value << 2, 463 + 0, maxpower); 464 + bcm43xx_phy_xmitpower(bcm); 465 + } 466 + err = 0; 467 + 468 + out_unlock: 469 + bcm43xx_unlock_mmio(bcm, flags); 470 + 471 + return err; 472 + } 473 + 474 + static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, 475 + struct iw_request_info *info, 476 + union iwreq_data *data, 477 + char *extra) 478 + { 479 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 480 + struct bcm43xx_radioinfo *radio; 481 + unsigned long flags; 482 + int err = -ENODEV; 483 + 484 + bcm43xx_lock(bcm, flags); 485 + if (!bcm->initialized) 486 + goto out_unlock; 487 + radio = bcm43xx_current_radio(bcm); 488 + /* desired dBm value is in Q5.2 */ 489 + data->txpower.value = radio->txpower_desired >> 2; 490 + data->txpower.fixed = 1; 491 + data->txpower.flags = IW_TXPOW_DBM; 492 + data->txpower.disabled = !(radio->enabled); 493 + 494 + err = 0; 495 + out_unlock: 496 + bcm43xx_unlock(bcm, flags); 497 + 498 + return err; 499 + } 500 + 501 + static int bcm43xx_wx_set_encoding(struct net_device *net_dev, 502 + struct iw_request_info *info, 503 + union iwreq_data *data, 504 + char *extra) 505 + { 506 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 507 + int err; 508 + 509 + err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); 510 + 511 + return err; 512 + } 513 + 514 + static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, 515 + struct iw_request_info *info, 516 + union iwreq_data *data, 517 + char *extra) 518 + { 519 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 520 + int err; 521 + 522 + err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); 523 + 524 + return err; 525 + } 526 + 527 + static int bcm43xx_wx_get_encoding(struct net_device *net_dev, 528 + struct iw_request_info *info, 529 + union iwreq_data *data, 530 + char *extra) 531 + { 532 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 533 + int err; 534 + 535 + err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); 536 + 537 + return err; 538 + } 539 + 540 + static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, 541 + struct iw_request_info *info, 542 + union iwreq_data *data, 543 + char *extra) 544 + { 545 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 546 + int err; 547 + 548 + err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); 549 + 550 + return err; 551 + } 552 + 553 + static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, 554 + struct iw_request_info *info, 555 + union iwreq_data *data, 556 + char *extra) 557 + { 558 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 559 + unsigned long flags; 560 + int mode, err = 0; 561 + 562 + mode = *((int *)extra); 563 + switch (mode) { 564 + case 0: 565 + mode = BCM43xx_RADIO_INTERFMODE_NONE; 566 + break; 567 + case 1: 568 + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; 569 + break; 570 + case 2: 571 + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; 572 + break; 573 + case 3: 574 + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; 575 + break; 576 + default: 577 + printk(KERN_ERR PFX "set_interfmode allowed parameters are: " 578 + "0 => None, 1 => Non-WLAN, 2 => WLAN, " 579 + "3 => Auto-WLAN\n"); 580 + return -EINVAL; 581 + } 582 + 583 + bcm43xx_lock_mmio(bcm, flags); 584 + if (bcm->initialized) { 585 + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); 586 + if (err) { 587 + printk(KERN_ERR PFX "Interference Mitigation not " 588 + "supported by device\n"); 589 + } 590 + } else { 591 + if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) { 592 + printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN " 593 + "not supported while the interface is down.\n"); 594 + err = -ENODEV; 595 + } else 596 + bcm43xx_current_radio(bcm)->interfmode = mode; 597 + } 598 + bcm43xx_unlock_mmio(bcm, flags); 599 + 600 + return err; 601 + } 602 + 603 + static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, 604 + struct iw_request_info *info, 605 + union iwreq_data *data, 606 + char *extra) 607 + { 608 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 609 + unsigned long flags; 610 + int mode; 611 + 612 + bcm43xx_lock(bcm, flags); 613 + mode = bcm43xx_current_radio(bcm)->interfmode; 614 + bcm43xx_unlock(bcm, flags); 615 + 616 + switch (mode) { 617 + case BCM43xx_RADIO_INTERFMODE_NONE: 618 + strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING); 619 + break; 620 + case BCM43xx_RADIO_INTERFMODE_NONWLAN: 621 + strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING); 622 + break; 623 + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: 624 + strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING); 625 + break; 626 + default: 627 + assert(0); 628 + } 629 + data->data.length = strlen(extra) + 1; 630 + 631 + return 0; 632 + } 633 + 634 + static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, 635 + struct iw_request_info *info, 636 + union iwreq_data *data, 637 + char *extra) 638 + { 639 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 640 + unsigned long flags; 641 + int on; 642 + 643 + on = *((int *)extra); 644 + bcm43xx_lock(bcm, flags); 645 + bcm->short_preamble = !!on; 646 + bcm43xx_unlock(bcm, flags); 647 + 648 + return 0; 649 + } 650 + 651 + static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, 652 + struct iw_request_info *info, 653 + union iwreq_data *data, 654 + char *extra) 655 + { 656 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 657 + unsigned long flags; 658 + int on; 659 + 660 + bcm43xx_lock(bcm, flags); 661 + on = bcm->short_preamble; 662 + bcm43xx_unlock(bcm, flags); 663 + 664 + if (on) 665 + strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); 666 + else 667 + strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING); 668 + data->data.length = strlen(extra) + 1; 669 + 670 + return 0; 671 + } 672 + 673 + static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, 674 + struct iw_request_info *info, 675 + union iwreq_data *data, 676 + char *extra) 677 + { 678 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 679 + unsigned long flags; 680 + int on; 681 + 682 + on = *((int *)extra); 683 + 684 + bcm43xx_lock(bcm, flags); 685 + bcm->ieee->host_encrypt = !!on; 686 + bcm->ieee->host_decrypt = !!on; 687 + bcm->ieee->host_build_iv = !on; 688 + bcm43xx_unlock(bcm, flags); 689 + 690 + return 0; 691 + } 692 + 693 + static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, 694 + struct iw_request_info *info, 695 + union iwreq_data *data, 696 + char *extra) 697 + { 698 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 699 + unsigned long flags; 700 + int on; 701 + 702 + bcm43xx_lock(bcm, flags); 703 + on = bcm->ieee->host_encrypt; 704 + bcm43xx_unlock(bcm, flags); 705 + 706 + if (on) 707 + strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); 708 + else 709 + strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); 710 + data->data.length = strlen(extra + 1); 711 + 712 + return 0; 713 + } 714 + 715 + /* Enough buffer to hold a hexdump of the sprom data. */ 716 + #define SPROM_BUFFERSIZE 512 717 + 718 + static int sprom2hex(const u16 *sprom, char *dump) 719 + { 720 + int i, pos = 0; 721 + 722 + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { 723 + pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1, 724 + "%04X", swab16(sprom[i]) & 0xFFFF); 725 + } 726 + 727 + return pos + 1; 728 + } 729 + 730 + static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) 731 + { 732 + char tmp[5] = { 0 }; 733 + int cnt = 0; 734 + unsigned long parsed; 735 + 736 + if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) 737 + return -EINVAL; 738 + while (cnt < BCM43xx_SPROM_SIZE) { 739 + memcpy(tmp, dump, 4); 740 + dump += 4; 741 + parsed = simple_strtoul(tmp, NULL, 16); 742 + sprom[cnt++] = swab16((u16)parsed); 743 + } 744 + 745 + return 0; 746 + } 747 + 748 + static int bcm43xx_wx_sprom_read(struct net_device *net_dev, 749 + struct iw_request_info *info, 750 + union iwreq_data *data, 751 + char *extra) 752 + { 753 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 754 + int err = -EPERM; 755 + u16 *sprom; 756 + unsigned long flags; 757 + 758 + if (!capable(CAP_SYS_RAWIO)) 759 + goto out; 760 + 761 + err = -ENOMEM; 762 + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), 763 + GFP_KERNEL); 764 + if (!sprom) 765 + goto out; 766 + 767 + bcm43xx_lock_mmio(bcm, flags); 768 + err = -ENODEV; 769 + if (bcm->initialized) 770 + err = bcm43xx_sprom_read(bcm, sprom); 771 + bcm43xx_unlock_mmio(bcm, flags); 772 + if (!err) 773 + data->data.length = sprom2hex(sprom, extra); 774 + kfree(sprom); 775 + out: 776 + return err; 777 + } 778 + 779 + static int bcm43xx_wx_sprom_write(struct net_device *net_dev, 780 + struct iw_request_info *info, 781 + union iwreq_data *data, 782 + char *extra) 783 + { 784 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 785 + int err = -EPERM; 786 + u16 *sprom; 787 + unsigned long flags; 788 + char *input; 789 + unsigned int len; 790 + 791 + if (!capable(CAP_SYS_RAWIO)) 792 + goto out; 793 + 794 + err = -ENOMEM; 795 + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), 796 + GFP_KERNEL); 797 + if (!sprom) 798 + goto out; 799 + 800 + len = data->data.length; 801 + extra[len - 1] = '\0'; 802 + input = strchr(extra, ':'); 803 + if (input) { 804 + input++; 805 + len -= input - extra; 806 + } else 807 + input = extra; 808 + err = hex2sprom(sprom, input, len); 809 + if (err) 810 + goto out_kfree; 811 + 812 + bcm43xx_lock_mmio(bcm, flags); 813 + err = -ENODEV; 814 + if (bcm->initialized) 815 + err = bcm43xx_sprom_write(bcm, sprom); 816 + bcm43xx_unlock_mmio(bcm, flags); 817 + out_kfree: 818 + kfree(sprom); 819 + out: 820 + return err; 821 + } 822 + 823 + /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ 824 + 825 + static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev) 826 + { 827 + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 828 + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); 829 + struct iw_statistics *wstats; 830 + 831 + wstats = &bcm->stats.wstats; 832 + if (!mac->associated) { 833 + wstats->miss.beacon = 0; 834 + // bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here? 835 + wstats->discard.retries = 0; 836 + // bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question 837 + wstats->discard.nwid = 0; 838 + // bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto 839 + wstats->discard.code = 0; 840 + // bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here 841 + wstats->discard.fragment = 0; 842 + wstats->discard.misc = 0; 843 + wstats->qual.qual = 0; 844 + wstats->qual.level = 0; 845 + wstats->qual.noise = 0; 846 + wstats->qual.updated = 7; 847 + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | 848 + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; 849 + return wstats; 850 + } 851 + /* fill in the real statistics when iface associated */ 852 + wstats->qual.qual = 100; // TODO: get the real signal quality 853 + wstats->qual.level = 3 - bcm->stats.link_quality; 854 + wstats->qual.noise = bcm->stats.noise; 855 + wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | 856 + IW_QUAL_NOISE_UPDATED; 857 + wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; 858 + wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; 859 + wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; 860 + wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments; 861 + wstats->discard.misc = 0; // FIXME 862 + wstats->miss.beacon = 0; // FIXME 863 + return wstats; 864 + } 865 + 866 + 867 + #ifdef WX 868 + # undef WX 869 + #endif 870 + #define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT] 871 + static const iw_handler bcm43xx_wx_handlers[] = { 872 + /* Wireless Identification */ 873 + WX(SIOCGIWNAME) = bcm43xx_wx_get_name, 874 + /* Basic operations */ 875 + WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq, 876 + WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq, 877 + WX(SIOCSIWMODE) = bcm43xx_wx_set_mode, 878 + WX(SIOCGIWMODE) = bcm43xx_wx_get_mode, 879 + /* Informative stuff */ 880 + WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams, 881 + /* Access Point manipulation */ 882 + WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, 883 + WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, 884 + WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, 885 + WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, 886 + /* 802.11 specific support */ 887 + WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, 888 + WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, 889 + WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick, 890 + WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick, 891 + /* Other parameters */ 892 + WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, 893 + WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, 894 + WX(SIOCSIWRTS) = bcm43xx_wx_set_rts, 895 + WX(SIOCGIWRTS) = bcm43xx_wx_get_rts, 896 + WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag, 897 + WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag, 898 + WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower, 899 + WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower, 900 + //TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry, 901 + //TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry, 902 + /* Encoding */ 903 + WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding, 904 + WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding, 905 + WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext, 906 + WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext, 907 + /* Power saving */ 908 + //TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power, 909 + //TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power, 910 + WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, 911 + WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, 912 + WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, 913 + WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, 914 + }; 915 + #undef WX 916 + 917 + static const iw_handler bcm43xx_priv_wx_handlers[] = { 918 + /* Set Interference Mitigation Mode. */ 919 + bcm43xx_wx_set_interfmode, 920 + /* Get Interference Mitigation Mode. */ 921 + bcm43xx_wx_get_interfmode, 922 + /* Enable/Disable Short Preamble mode. */ 923 + bcm43xx_wx_set_shortpreamble, 924 + /* Get Short Preamble mode. */ 925 + bcm43xx_wx_get_shortpreamble, 926 + /* Enable/Disable Software Encryption mode */ 927 + bcm43xx_wx_set_swencryption, 928 + /* Get Software Encryption mode */ 929 + bcm43xx_wx_get_swencryption, 930 + /* Write SRPROM data. */ 931 + bcm43xx_wx_sprom_write, 932 + /* Read SPROM data. */ 933 + bcm43xx_wx_sprom_read, 934 + }; 935 + 936 + #define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0) 937 + #define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1) 938 + #define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2) 939 + #define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3) 940 + #define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4) 941 + #define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5) 942 + #define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6) 943 + #define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7) 944 + 945 + #define PRIV_WX_DUMMY(ioctl) \ 946 + { \ 947 + .cmd = (ioctl), \ 948 + .name = "__unused" \ 949 + } 950 + 951 + static const struct iw_priv_args bcm43xx_priv_wx_args[] = { 952 + { 953 + .cmd = PRIV_WX_SET_INTERFMODE, 954 + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 955 + .name = "set_interfmode", 956 + }, 957 + { 958 + .cmd = PRIV_WX_GET_INTERFMODE, 959 + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 960 + .name = "get_interfmode", 961 + }, 962 + { 963 + .cmd = PRIV_WX_SET_SHORTPREAMBLE, 964 + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 965 + .name = "set_shortpreambl", 966 + }, 967 + { 968 + .cmd = PRIV_WX_GET_SHORTPREAMBLE, 969 + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 970 + .name = "get_shortpreambl", 971 + }, 972 + { 973 + .cmd = PRIV_WX_SET_SWENCRYPTION, 974 + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 975 + .name = "set_swencryption", 976 + }, 977 + { 978 + .cmd = PRIV_WX_GET_SWENCRYPTION, 979 + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, 980 + .name = "get_swencryption", 981 + }, 982 + { 983 + .cmd = PRIV_WX_SPROM_WRITE, 984 + .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE, 985 + .name = "write_sprom", 986 + }, 987 + { 988 + .cmd = PRIV_WX_SPROM_READ, 989 + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE, 990 + .name = "read_sprom", 991 + }, 992 + }; 993 + 994 + const struct iw_handler_def bcm43xx_wx_handlers_def = { 995 + .standard = bcm43xx_wx_handlers, 996 + .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers), 997 + .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers), 998 + .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), 999 + .private = bcm43xx_priv_wx_handlers, 1000 + .private_args = bcm43xx_priv_wx_args, 1001 + .get_wireless_stats = bcm43xx_get_wireless_stats, 1002 + };
+36
drivers/net/wireless/bcm43xx/bcm43xx_wx.h
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 6 + Stefano Brivio <st3@riseup.net> 7 + Michael Buesch <mbuesch@freenet.de> 8 + Danny van Dyk <kugelfang@gentoo.org> 9 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 + 11 + Some parts of the code in this file are derived from the ipw2200 12 + driver Copyright(c) 2003 - 2004 Intel Corporation. 13 + 14 + This program is free software; you can redistribute it and/or modify 15 + it under the terms of the GNU General Public License as published by 16 + the Free Software Foundation; either version 2 of the License, or 17 + (at your option) any later version. 18 + 19 + This program is distributed in the hope that it will be useful, 20 + but WITHOUT ANY WARRANTY; without even the implied warranty of 21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 + GNU General Public License for more details. 23 + 24 + You should have received a copy of the GNU General Public License 25 + along with this program; see the file COPYING. If not, write to 26 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 27 + Boston, MA 02110-1301, USA. 28 + 29 + */ 30 + 31 + #ifndef BCM43xx_WX_H_ 32 + #define BCM43xx_WX_H_ 33 + 34 + extern const struct iw_handler_def bcm43xx_wx_handlers_def; 35 + 36 + #endif /* BCM43xx_WX_H_ */
+582
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
··· 1 + /* 2 + 3 + Broadcom BCM43xx wireless driver 4 + 5 + Transmission (TX/RX) related functions. 6 + 7 + Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 8 + Stefano Brivio <st3@riseup.net> 9 + Michael Buesch <mbuesch@freenet.de> 10 + Danny van Dyk <kugelfang@gentoo.org> 11 + Andreas Jaggi <andreas.jaggi@waterwave.ch> 12 + 13 + This program is free software; you can redistribute it and/or modify 14 + it under the terms of the GNU General Public License as published by 15 + the Free Software Foundation; either version 2 of the License, or 16 + (at your option) any later version. 17 + 18 + This program is distributed in the hope that it will be useful, 19 + but WITHOUT ANY WARRANTY; without even the implied warranty of 20 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 + GNU General Public License for more details. 22 + 23 + You should have received a copy of the GNU General Public License 24 + along with this program; see the file COPYING. If not, write to 25 + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 26 + Boston, MA 02110-1301, USA. 27 + 28 + */ 29 + 30 + #include "bcm43xx_xmit.h" 31 + 32 + #include <linux/etherdevice.h> 33 + 34 + 35 + /* Extract the bitrate out of a CCK PLCP header. */ 36 + static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp) 37 + { 38 + switch (plcp->raw[0]) { 39 + case 0x0A: 40 + return IEEE80211_CCK_RATE_1MB; 41 + case 0x14: 42 + return IEEE80211_CCK_RATE_2MB; 43 + case 0x37: 44 + return IEEE80211_CCK_RATE_5MB; 45 + case 0x6E: 46 + return IEEE80211_CCK_RATE_11MB; 47 + } 48 + assert(0); 49 + return 0; 50 + } 51 + 52 + /* Extract the bitrate out of an OFDM PLCP header. */ 53 + static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp) 54 + { 55 + switch (plcp->raw[0] & 0xF) { 56 + case 0xB: 57 + return IEEE80211_OFDM_RATE_6MB; 58 + case 0xF: 59 + return IEEE80211_OFDM_RATE_9MB; 60 + case 0xA: 61 + return IEEE80211_OFDM_RATE_12MB; 62 + case 0xE: 63 + return IEEE80211_OFDM_RATE_18MB; 64 + case 0x9: 65 + return IEEE80211_OFDM_RATE_24MB; 66 + case 0xD: 67 + return IEEE80211_OFDM_RATE_36MB; 68 + case 0x8: 69 + return IEEE80211_OFDM_RATE_48MB; 70 + case 0xC: 71 + return IEEE80211_OFDM_RATE_54MB; 72 + } 73 + assert(0); 74 + return 0; 75 + } 76 + 77 + u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) 78 + { 79 + switch (bitrate) { 80 + case IEEE80211_CCK_RATE_1MB: 81 + return 0x0A; 82 + case IEEE80211_CCK_RATE_2MB: 83 + return 0x14; 84 + case IEEE80211_CCK_RATE_5MB: 85 + return 0x37; 86 + case IEEE80211_CCK_RATE_11MB: 87 + return 0x6E; 88 + } 89 + assert(0); 90 + return 0; 91 + } 92 + 93 + u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) 94 + { 95 + switch (bitrate) { 96 + case IEEE80211_OFDM_RATE_6MB: 97 + return 0xB; 98 + case IEEE80211_OFDM_RATE_9MB: 99 + return 0xF; 100 + case IEEE80211_OFDM_RATE_12MB: 101 + return 0xA; 102 + case IEEE80211_OFDM_RATE_18MB: 103 + return 0xE; 104 + case IEEE80211_OFDM_RATE_24MB: 105 + return 0x9; 106 + case IEEE80211_OFDM_RATE_36MB: 107 + return 0xD; 108 + case IEEE80211_OFDM_RATE_48MB: 109 + return 0x8; 110 + case IEEE80211_OFDM_RATE_54MB: 111 + return 0xC; 112 + } 113 + assert(0); 114 + return 0; 115 + } 116 + 117 + static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, 118 + const u16 octets, const u8 bitrate, 119 + const int ofdm_modulation) 120 + { 121 + __le32 *data = &(plcp->data); 122 + __u8 *raw = plcp->raw; 123 + 124 + if (ofdm_modulation) { 125 + *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); 126 + assert(!(octets & 0xF000)); 127 + *data |= (octets << 5); 128 + *data = cpu_to_le32(*data); 129 + } else { 130 + u32 plen; 131 + 132 + plen = octets * 16 / bitrate; 133 + if ((octets * 16 % bitrate) > 0) { 134 + plen++; 135 + if ((bitrate == IEEE80211_CCK_RATE_11MB) 136 + && ((octets * 8 % 11) < 4)) { 137 + raw[1] = 0x84; 138 + } else 139 + raw[1] = 0x04; 140 + } else 141 + raw[1] = 0x04; 142 + *data |= cpu_to_le32(plen << 16); 143 + raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); 144 + } 145 + } 146 + 147 + static u8 bcm43xx_calc_fallback_rate(u8 bitrate) 148 + { 149 + switch (bitrate) { 150 + case IEEE80211_CCK_RATE_1MB: 151 + return IEEE80211_CCK_RATE_1MB; 152 + case IEEE80211_CCK_RATE_2MB: 153 + return IEEE80211_CCK_RATE_1MB; 154 + case IEEE80211_CCK_RATE_5MB: 155 + return IEEE80211_CCK_RATE_2MB; 156 + case IEEE80211_CCK_RATE_11MB: 157 + return IEEE80211_CCK_RATE_5MB; 158 + case IEEE80211_OFDM_RATE_6MB: 159 + return IEEE80211_CCK_RATE_5MB; 160 + case IEEE80211_OFDM_RATE_9MB: 161 + return IEEE80211_OFDM_RATE_6MB; 162 + case IEEE80211_OFDM_RATE_12MB: 163 + return IEEE80211_OFDM_RATE_9MB; 164 + case IEEE80211_OFDM_RATE_18MB: 165 + return IEEE80211_OFDM_RATE_12MB; 166 + case IEEE80211_OFDM_RATE_24MB: 167 + return IEEE80211_OFDM_RATE_18MB; 168 + case IEEE80211_OFDM_RATE_36MB: 169 + return IEEE80211_OFDM_RATE_24MB; 170 + case IEEE80211_OFDM_RATE_48MB: 171 + return IEEE80211_OFDM_RATE_36MB; 172 + case IEEE80211_OFDM_RATE_54MB: 173 + return IEEE80211_OFDM_RATE_48MB; 174 + } 175 + assert(0); 176 + return 0; 177 + } 178 + 179 + static 180 + __le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header, 181 + u8 bitrate) 182 + { 183 + const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl); 184 + __le16 duration_id = wireless_header->duration_id; 185 + 186 + switch (WLAN_FC_GET_TYPE(frame_ctl)) { 187 + case IEEE80211_FTYPE_DATA: 188 + case IEEE80211_FTYPE_MGMT: 189 + //TODO: Steal the code from ieee80211, once it is completed there. 190 + break; 191 + case IEEE80211_FTYPE_CTL: 192 + /* Use the original duration/id. */ 193 + break; 194 + default: 195 + assert(0); 196 + } 197 + 198 + return duration_id; 199 + } 200 + 201 + static inline 202 + u16 ceiling_div(u16 dividend, u16 divisor) 203 + { 204 + return ((dividend + divisor - 1) / divisor); 205 + } 206 + 207 + static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, 208 + struct bcm43xx_txhdr *txhdr, 209 + u16 *flags, 210 + u8 bitrate, 211 + const struct ieee80211_hdr_4addr *wlhdr) 212 + { 213 + u16 fctl; 214 + u16 dur; 215 + u8 fallback_bitrate; 216 + int ofdm_modulation; 217 + int fallback_ofdm_modulation; 218 + // u8 *sa, *da; 219 + u16 flen; 220 + 221 + //FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr); 222 + //FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr); 223 + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); 224 + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); 225 + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); 226 + 227 + flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN, 228 + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp), 229 + flen, bitrate, 230 + !ieee80211_is_cck_rate(bitrate)); 231 + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp), 232 + flen, fallback_bitrate, 233 + !ieee80211_is_cck_rate(fallback_bitrate)); 234 + fctl = IEEE80211_FTYPE_CTL; 235 + fctl |= IEEE80211_STYPE_RTS; 236 + dur = le16_to_cpu(wlhdr->duration_id); 237 + /*FIXME: should we test for dur==0 here and let it unmodified in this case? 238 + * The following assert checks for this case... 239 + */ 240 + assert(dur); 241 + /*FIXME: The duration calculation is not really correct. 242 + * I am not 100% sure which bitrate to use. We use the RTS rate here, 243 + * but this is likely to be wrong. 244 + */ 245 + if (phy->type == BCM43xx_PHYTYPE_A) { 246 + /* Three times SIFS */ 247 + dur += 16 * 3; 248 + /* Add ACK duration. */ 249 + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, 250 + bitrate * 4); 251 + /* Add CTS duration. */ 252 + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, 253 + bitrate * 4); 254 + } else { 255 + /* Three times SIFS */ 256 + dur += 10 * 3; 257 + /* Add ACK duration. */ 258 + dur += ceiling_div(8 * (14 /*bytes*/) * 10, 259 + bitrate); 260 + /* Add CTS duration. */ 261 + dur += ceiling_div(8 * (14 /*bytes*/) * 10, 262 + bitrate); 263 + } 264 + 265 + txhdr->rts_cts_frame_control = cpu_to_le16(fctl); 266 + txhdr->rts_cts_dur = cpu_to_le16(dur); 267 + //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); 268 + //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); 269 + memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME! 270 + // memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); 271 + 272 + *flags |= BCM43xx_TXHDRFLAG_RTSCTS; 273 + *flags |= BCM43xx_TXHDRFLAG_RTS; 274 + if (ofdm_modulation) 275 + *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM; 276 + if (fallback_ofdm_modulation) 277 + *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM; 278 + } 279 + 280 + void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, 281 + struct bcm43xx_txhdr *txhdr, 282 + const unsigned char *fragment_data, 283 + const unsigned int fragment_len, 284 + const int is_first_fragment, 285 + const u16 cookie) 286 + { 287 + const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 288 + const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; 289 + const struct ieee80211_security *secinfo = &bcm->ieee->sec; 290 + u8 bitrate; 291 + u8 fallback_bitrate; 292 + int ofdm_modulation; 293 + int fallback_ofdm_modulation; 294 + u16 plcp_fragment_len = fragment_len; 295 + u16 flags = 0; 296 + u16 control = 0; 297 + u16 wsec_rate = 0; 298 + u16 encrypt_frame; 299 + 300 + /* Now construct the TX header. */ 301 + memset(txhdr, 0, sizeof(*txhdr)); 302 + 303 + bitrate = bcm->softmac->txrates.default_rate; 304 + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); 305 + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); 306 + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); 307 + 308 + /* Set Frame Control from 80211 header. */ 309 + txhdr->frame_control = wireless_header->frame_ctl; 310 + /* Copy address1 from 80211 header. */ 311 + memcpy(txhdr->mac1, wireless_header->addr1, 6); 312 + /* Set the fallback duration ID. */ 313 + txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header, 314 + fallback_bitrate); 315 + /* Set the cookie (used as driver internal ID for the frame) */ 316 + txhdr->cookie = cpu_to_le16(cookie); 317 + 318 + /* Hardware appends FCS. */ 319 + plcp_fragment_len += IEEE80211_FCS_LEN; 320 + 321 + /* Hardware encryption. */ 322 + encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; 323 + if (encrypt_frame && !bcm->ieee->host_encrypt) { 324 + const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; 325 + memcpy(txhdr->wep_iv, hdr->payload, 4); 326 + /* Hardware appends ICV. */ 327 + plcp_fragment_len += 4; 328 + 329 + wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) 330 + & BCM43xx_TXHDR_WSEC_ALGO_MASK; 331 + wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) 332 + & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; 333 + } 334 + 335 + /* Generate the PLCP header and the fallback PLCP header. */ 336 + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), 337 + plcp_fragment_len, 338 + bitrate, ofdm_modulation); 339 + bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len, 340 + fallback_bitrate, fallback_ofdm_modulation); 341 + 342 + /* Set the CONTROL field */ 343 + if (ofdm_modulation) 344 + control |= BCM43xx_TXHDRCTL_OFDM; 345 + if (bcm->short_preamble) //FIXME: could be the other way around, please test 346 + control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; 347 + control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) 348 + & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; 349 + 350 + /* Set the FLAGS field */ 351 + if (!is_multicast_ether_addr(wireless_header->addr1) && 352 + !is_broadcast_ether_addr(wireless_header->addr1)) 353 + flags |= BCM43xx_TXHDRFLAG_EXPECTACK; 354 + if (1 /* FIXME: PS poll?? */) 355 + flags |= 0x10; // FIXME: unknown meaning. 356 + if (fallback_ofdm_modulation) 357 + flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; 358 + if (is_first_fragment) 359 + flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; 360 + 361 + /* Set WSEC/RATE field */ 362 + wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT) 363 + & BCM43xx_TXHDR_RATE_MASK; 364 + 365 + /* Generate the RTS/CTS packet, if required. */ 366 + /* FIXME: We should first try with CTS-to-self, 367 + * if we are on 80211g. If we get too many 368 + * failures (hidden nodes), we should switch back to RTS/CTS. 369 + */ 370 + if (0/*FIXME txctl->use_rts_cts*/) { 371 + bcm43xx_generate_rts(phy, txhdr, &flags, 372 + 0/*FIXME txctl->rts_cts_rate*/, 373 + wireless_header); 374 + } 375 + 376 + txhdr->flags = cpu_to_le16(flags); 377 + txhdr->control = cpu_to_le16(control); 378 + txhdr->wsec_rate = cpu_to_le16(wsec_rate); 379 + } 380 + 381 + static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, 382 + u8 in_rssi, int ofdm, 383 + int adjust_2053, int adjust_2050) 384 + { 385 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 386 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 387 + s32 tmp; 388 + 389 + switch (radio->version) { 390 + case 0x2050: 391 + if (ofdm) { 392 + tmp = in_rssi; 393 + if (tmp > 127) 394 + tmp -= 256; 395 + tmp *= 73; 396 + tmp /= 64; 397 + if (adjust_2050) 398 + tmp += 25; 399 + else 400 + tmp -= 3; 401 + } else { 402 + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { 403 + if (in_rssi > 63) 404 + in_rssi = 63; 405 + tmp = radio->nrssi_lt[in_rssi]; 406 + tmp = 31 - tmp; 407 + tmp *= -131; 408 + tmp /= 128; 409 + tmp -= 57; 410 + } else { 411 + tmp = in_rssi; 412 + tmp = 31 - tmp; 413 + tmp *= -149; 414 + tmp /= 128; 415 + tmp -= 68; 416 + } 417 + if (phy->type == BCM43xx_PHYTYPE_G && 418 + adjust_2050) 419 + tmp += 25; 420 + } 421 + break; 422 + case 0x2060: 423 + if (in_rssi > 127) 424 + tmp = in_rssi - 256; 425 + else 426 + tmp = in_rssi; 427 + break; 428 + default: 429 + tmp = in_rssi; 430 + tmp -= 11; 431 + tmp *= 103; 432 + tmp /= 64; 433 + if (adjust_2053) 434 + tmp -= 109; 435 + else 436 + tmp -= 83; 437 + } 438 + 439 + return (s8)tmp; 440 + } 441 + 442 + //TODO 443 + #if 0 444 + static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, 445 + u8 in_rssi) 446 + { 447 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 448 + s8 ret; 449 + 450 + if (phy->type == BCM43xx_PHYTYPE_A) { 451 + //TODO: Incomplete specs. 452 + ret = 0; 453 + } else 454 + ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); 455 + 456 + return ret; 457 + } 458 + #endif 459 + 460 + int bcm43xx_rx(struct bcm43xx_private *bcm, 461 + struct sk_buff *skb, 462 + struct bcm43xx_rxhdr *rxhdr) 463 + { 464 + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 465 + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 466 + struct bcm43xx_plcp_hdr4 *plcp; 467 + struct ieee80211_rx_stats stats; 468 + struct ieee80211_hdr_4addr *wlhdr; 469 + u16 frame_ctl; 470 + int is_packet_for_us = 0; 471 + int err = -EINVAL; 472 + const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); 473 + const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); 474 + const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); 475 + const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); 476 + 477 + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { 478 + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); 479 + /* Skip two unknown bytes and the PLCP header. */ 480 + skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); 481 + } else { 482 + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); 483 + /* Skip the PLCP header. */ 484 + skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); 485 + } 486 + /* The SKB contains the PAYLOAD (wireless header + data) 487 + * at this point. The FCS at the end is stripped. 488 + */ 489 + 490 + memset(&stats, 0, sizeof(stats)); 491 + stats.mac_time = le16_to_cpu(rxhdr->mactime); 492 + stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, 493 + !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), 494 + !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); 495 + stats.signal = rxhdr->signal_quality; //FIXME 496 + //TODO stats.noise = 497 + if (is_ofdm) 498 + stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); 499 + else 500 + stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); 501 + //printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); 502 + stats.received_channel = radio->channel; 503 + //TODO stats.control = 504 + stats.mask = IEEE80211_STATMASK_SIGNAL | 505 + //TODO IEEE80211_STATMASK_NOISE | 506 + IEEE80211_STATMASK_RATE | 507 + IEEE80211_STATMASK_RSSI; 508 + if (phy->type == BCM43xx_PHYTYPE_A) 509 + stats.freq = IEEE80211_52GHZ_BAND; 510 + else 511 + stats.freq = IEEE80211_24GHZ_BAND; 512 + stats.len = skb->len; 513 + 514 + bcm->stats.last_rx = jiffies; 515 + if (bcm->ieee->iw_mode == IW_MODE_MONITOR) { 516 + err = ieee80211_rx(bcm->ieee, skb, &stats); 517 + return (err == 0) ? -EINVAL : 0; 518 + } 519 + 520 + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); 521 + 522 + switch (bcm->ieee->iw_mode) { 523 + case IW_MODE_ADHOC: 524 + if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || 525 + memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || 526 + is_broadcast_ether_addr(wlhdr->addr1) || 527 + is_multicast_ether_addr(wlhdr->addr1) || 528 + bcm->net_dev->flags & IFF_PROMISC) 529 + is_packet_for_us = 1; 530 + break; 531 + case IW_MODE_INFRA: 532 + default: 533 + /* When receiving multicast or broadcast packets, filter out 534 + the packets we send ourself; we shouldn't see those */ 535 + if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || 536 + memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || 537 + (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && 538 + (is_broadcast_ether_addr(wlhdr->addr1) || 539 + is_multicast_ether_addr(wlhdr->addr1) || 540 + bcm->net_dev->flags & IFF_PROMISC))) 541 + is_packet_for_us = 1; 542 + break; 543 + } 544 + 545 + frame_ctl = le16_to_cpu(wlhdr->frame_ctl); 546 + if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { 547 + frame_ctl &= ~IEEE80211_FCTL_PROTECTED; 548 + wlhdr->frame_ctl = cpu_to_le16(frame_ctl); 549 + /* trim IV and ICV */ 550 + /* FIXME: this must be done only for WEP encrypted packets */ 551 + if (skb->len < 32) { 552 + dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " 553 + "set and length < 32)\n"); 554 + return -EINVAL; 555 + } else { 556 + memmove(skb->data + 4, skb->data, 24); 557 + skb_pull(skb, 4); 558 + skb_trim(skb, skb->len - 4); 559 + stats.len -= 8; 560 + } 561 + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); 562 + } 563 + 564 + switch (WLAN_FC_GET_TYPE(frame_ctl)) { 565 + case IEEE80211_FTYPE_MGMT: 566 + ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); 567 + break; 568 + case IEEE80211_FTYPE_DATA: 569 + if (is_packet_for_us) { 570 + err = ieee80211_rx(bcm->ieee, skb, &stats); 571 + err = (err == 0) ? -EINVAL : 0; 572 + } 573 + break; 574 + case IEEE80211_FTYPE_CTL: 575 + break; 576 + default: 577 + assert(0); 578 + return -EINVAL; 579 + } 580 + 581 + return err; 582 + }
+156
drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
··· 1 + #ifndef BCM43xx_XMIT_H_ 2 + #define BCM43xx_XMIT_H_ 3 + 4 + #include "bcm43xx_main.h" 5 + 6 + 7 + #define _bcm43xx_declare_plcp_hdr(size) \ 8 + struct bcm43xx_plcp_hdr##size { \ 9 + union { \ 10 + __le32 data; \ 11 + __u8 raw[size]; \ 12 + } __attribute__((__packed__)); \ 13 + } __attribute__((__packed__)) 14 + 15 + /* struct bcm43xx_plcp_hdr4 */ 16 + _bcm43xx_declare_plcp_hdr(4); 17 + /* struct bcm43xx_plcp_hdr6 */ 18 + _bcm43xx_declare_plcp_hdr(6); 19 + 20 + #undef _bcm43xx_declare_plcp_hdr 21 + 22 + /* Device specific TX header. To be prepended to TX frames. */ 23 + struct bcm43xx_txhdr { 24 + union { 25 + struct { 26 + __le16 flags; 27 + __le16 wsec_rate; 28 + __le16 frame_control; 29 + u16 unknown_zeroed_0; 30 + __le16 control; 31 + u8 wep_iv[10]; 32 + u8 unknown_wsec_tkip_data[3]; //FIXME 33 + PAD_BYTES(3); 34 + u8 mac1[6]; 35 + u16 unknown_zeroed_1; 36 + struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; 37 + __le16 rts_cts_dur_fallback; 38 + struct bcm43xx_plcp_hdr4 fallback_plcp; 39 + __le16 fallback_dur_id; 40 + PAD_BYTES(2); 41 + __le16 cookie; 42 + __le16 unknown_scb_stuff; //FIXME 43 + struct bcm43xx_plcp_hdr6 rts_cts_plcp; 44 + __le16 rts_cts_frame_control; 45 + __le16 rts_cts_dur; 46 + u8 rts_cts_mac1[6]; 47 + u8 rts_cts_mac2[6]; 48 + PAD_BYTES(2); 49 + struct bcm43xx_plcp_hdr6 plcp; 50 + } __attribute__((__packed__)); 51 + u8 raw[82]; 52 + } __attribute__((__packed__)); 53 + } __attribute__((__packed__)); 54 + 55 + /* Values/Masks for the device TX header */ 56 + #define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 57 + #define BCM43xx_TXHDRFLAG_RTSCTS 0x0002 58 + #define BCM43xx_TXHDRFLAG_RTS 0x0004 59 + #define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 60 + #define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 61 + #define BCM43xx_TXHDRFLAG_RTSCTS_OFDM 0x0080 62 + #define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 63 + #define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM 0x0200 64 + #define BCM43xx_TXHDRFLAG_CTS 0x0400 65 + #define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 66 + 67 + #define BCM43xx_TXHDRCTL_OFDM 0x0001 68 + #define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 69 + #define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 70 + #define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 71 + 72 + #define BCM43xx_TXHDR_RATE_MASK 0x0F00 73 + #define BCM43xx_TXHDR_RATE_SHIFT 8 74 + #define BCM43xx_TXHDR_RTSRATE_MASK 0xF000 75 + #define BCM43xx_TXHDR_RTSRATE_SHIFT 12 76 + #define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 77 + #define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 78 + #define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 79 + #define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 80 + 81 + void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, 82 + struct bcm43xx_txhdr *txhdr, 83 + const unsigned char *fragment_data, 84 + const unsigned int fragment_len, 85 + const int is_first_fragment, 86 + const u16 cookie); 87 + 88 + /* RX header as received from the hardware. */ 89 + struct bcm43xx_rxhdr { 90 + /* Frame Length. Must be generated explicitely in PIO mode. */ 91 + __le16 frame_length; 92 + PAD_BYTES(2); 93 + /* Flags field 1 */ 94 + __le16 flags1; 95 + u8 rssi; 96 + u8 signal_quality; 97 + PAD_BYTES(2); 98 + /* Flags field 3 */ 99 + __le16 flags3; 100 + /* Flags field 2 */ 101 + __le16 flags2; 102 + /* Lower 16bits of the TSF at the time the frame started. */ 103 + __le16 mactime; 104 + PAD_BYTES(14); 105 + } __attribute__((__packed__)); 106 + 107 + #define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) 108 + /*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ 109 + #define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) 110 + #define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) 111 + 112 + #define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) 113 + #define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) 114 + /*FIXME: WEP related flags */ 115 + 116 + #define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) 117 + 118 + /* Transmit Status as received from the hardware. */ 119 + struct bcm43xx_hwxmitstatus { 120 + PAD_BYTES(4); 121 + __le16 cookie; 122 + u8 flags; 123 + u8 cnt1:4, 124 + cnt2:4; 125 + PAD_BYTES(2); 126 + __le16 seq; 127 + __le16 unknown; //FIXME 128 + } __attribute__((__packed__)); 129 + 130 + /* Transmit Status in CPU byteorder. */ 131 + struct bcm43xx_xmitstatus { 132 + u16 cookie; 133 + u8 flags; 134 + u8 cnt1:4, 135 + cnt2:4; 136 + u16 seq; 137 + u16 unknown; //FIXME 138 + }; 139 + 140 + #define BCM43xx_TXSTAT_FLAG_ACK 0x01 141 + //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 142 + //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 143 + //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 144 + //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 145 + #define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 146 + //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 147 + //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 148 + 149 + u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate); 150 + u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate); 151 + 152 + int bcm43xx_rx(struct bcm43xx_private *bcm, 153 + struct sk_buff *skb, 154 + struct bcm43xx_rxhdr *rxhdr); 155 + 156 + #endif /* BCM43xx_XMIT_H_ */
-2
drivers/net/wireless/hostap/hostap_80211.h
··· 92 92 void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); 93 93 int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); 94 94 int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); 95 - struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, 96 - struct ieee80211_crypt_data *crypt); 97 95 int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); 98 96 99 97 #endif /* HOSTAP_80211_H */
+4 -5
drivers/net/wireless/hostap/hostap_80211_tx.c
··· 299 299 300 300 301 301 /* Called only from software IRQ */ 302 - struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, 303 - struct ieee80211_crypt_data *crypt) 302 + static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, 303 + struct ieee80211_crypt_data *crypt) 304 304 { 305 305 struct hostap_interface *iface; 306 306 local_info_t *local; ··· 317 317 } 318 318 319 319 if (local->tkip_countermeasures && 320 - crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { 320 + strcmp(crypt->ops->name, "TKIP") == 0) { 321 321 hdr = (struct ieee80211_hdr_4addr *) skb->data; 322 322 if (net_ratelimit()) { 323 323 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " ··· 469 469 } 470 470 471 471 if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && 472 - !(fc & IEEE80211_FCTL_VERS)) { 472 + !(fc & IEEE80211_FCTL_PROTECTED)) { 473 473 no_encrypt = 1; 474 474 PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " 475 475 "unencrypted EAPOL frame\n", dev->name); ··· 535 535 536 536 537 537 EXPORT_SYMBOL(hostap_dump_tx_80211); 538 - EXPORT_SYMBOL(hostap_tx_encrypt); 539 538 EXPORT_SYMBOL(hostap_master_start_xmit);
+1 -1
drivers/usb/net/zd1201.c
··· 1736 1736 .standard = (iw_handler *)zd1201_iw_handler, 1737 1737 .private = (iw_handler *)zd1201_private_handler, 1738 1738 .private_args = (struct iw_priv_args *) zd1201_private_args, 1739 + .get_wireless_stats = zd1201_get_wireless_stats, 1739 1740 }; 1740 1741 1741 1742 static int zd1201_probe(struct usb_interface *interface, ··· 1797 1796 zd->dev->open = zd1201_net_open; 1798 1797 zd->dev->stop = zd1201_net_stop; 1799 1798 zd->dev->get_stats = zd1201_get_stats; 1800 - zd->dev->get_wireless_stats = zd1201_get_wireless_stats; 1801 1799 zd->dev->wireless_handlers = 1802 1800 (struct iw_handler_def *)&zd1201_iw_handlers; 1803 1801 zd->dev->hard_start_xmit = zd1201_hard_start_xmit;
+2 -2
net/ieee80211/ieee80211_wx.c
··· 42 42 }; 43 43 44 44 #define MAX_CUSTOM_LEN 64 45 - static char *ipw2100_translate_scan(struct ieee80211_device *ieee, 45 + static char *ieee80211_translate_scan(struct ieee80211_device *ieee, 46 46 char *start, char *stop, 47 47 struct ieee80211_network *network) 48 48 { ··· 274 274 275 275 if (ieee->scan_age == 0 || 276 276 time_after(network->last_scanned + ieee->scan_age, jiffies)) 277 - ev = ipw2100_translate_scan(ieee, ev, stop, network); 277 + ev = ieee80211_translate_scan(ieee, ev, stop, network); 278 278 else 279 279 IEEE80211_DEBUG_SCAN("Not showing network '%s (" 280 280 MAC_FMT ")' due to age (%dms).\n",
+11 -6
net/ieee80211/softmac/ieee80211softmac_module.c
··· 183 183 */ 184 184 if (mac->txrates_change) 185 185 oldrates = mac->txrates; 186 - if (ieee->modulation & IEEE80211_OFDM_MODULATION) { 187 - mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; 188 - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; 189 - mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB; 190 - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; 191 - } else if (ieee->modulation & IEEE80211_CCK_MODULATION) { 186 + /* FIXME: We don't correctly handle backing down to lower 187 + rates, so 801.11g devices start off at 11M for now. People 188 + can manually change it if they really need to, but 11M is 189 + more reliable. Note similar logic in 190 + ieee80211softmac_wx_set_rate() */ 191 + if (ieee->modulation & IEEE80211_CCK_MODULATION) { 192 192 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB; 193 193 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; 194 194 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB; 195 + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; 196 + } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { 197 + mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; 198 + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; 199 + mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB; 195 200 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; 196 201 } else 197 202 assert(0);
+1 -1
net/ieee80211/softmac/ieee80211softmac_priv.h
··· 167 167 ) || ieee80211softmac_scan_handlers_check_self(sm); 168 168 } 169 169 170 - #define IEEE80211SOFTMAC_PROBE_DELAY HZ/2 170 + #define IEEE80211SOFTMAC_PROBE_DELAY HZ/50 171 171 #define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ) 172 172 173 173 struct ieee80211softmac_network {
+8 -4
net/ieee80211/softmac/ieee80211softmac_wx.c
··· 135 135 int err = -EINVAL; 136 136 137 137 if (in_rate == -1) { 138 - /* automatic detect */ 139 - if (ieee->modulation & IEEE80211_OFDM_MODULATION) 140 - in_rate = 54000000; 141 - else 138 + /* FIXME: We don't correctly handle backing down to lower 139 + rates, so 801.11g devices start off at 11M for now. People 140 + can manually change it if they really need to, but 11M is 141 + more reliable. Note similar logic in 142 + ieee80211softmac_wx_set_rate() */ 143 + if (ieee->modulation & IEEE80211_CCK_MODULATION) 142 144 in_rate = 11000000; 145 + else 146 + in_rate = 54000000; 143 147 } 144 148 145 149 switch (in_rate) {