New: mac80211-based bcm43xx driver from the wireless-dev tree

SVN-Revision: 7693
This commit is contained in:
Peter Denison 2007-06-21 20:45:45 +00:00
parent 65f00ab51a
commit 45a0adebf9
31 changed files with 16363 additions and 0 deletions

View file

@ -0,0 +1,53 @@
#
# Copyright (C) 2007 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# $Id: Makefile 7440 2007-06-02 02:22:01Z nbd $
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=bcm43xx-mac80211
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
# This horrible, horrible hack is because I can't work out ow to add
# CONFIG_* definitions to a kernel config from an external module dir.
# It should come from a proper configuration based on the Kconfig in the src
# directory.
MAKE_CONFIGS=CONFIG_BCM43XX_MAC80211=m CONFIG_BCM43XX_MAC80211_PCI=y \
CONFIG_BCM43XX_MAC80211_DEBUG=y CONFIG_BCM43XX_MAC80211_DMA=y \
CONFIG_BCM43XX_MAC80211_PIO=y CONFIG_BCM43XX_MAC80211_DMA_AND_PIO_MODE=y
BUILDFLAGS+=$(patsubst CONFIG_%, -DCONFIG_%, $(MAKE_CONFIGS))
define KernelPackage/bcm43xx-mac80211
TITLE:=Broadcom 43xx wireless support
DESCRIPTION:=Kernel module for Broadcom 43xx wireless support (mac80211)
VERSION:=$(PKG_RELEASE)+$(LINUX_VERSION)-$(BOARD)-$(LINUX_RELEASE)
DEPENDS:=@LINUX_2_6 +kmod-mac80211
SUBMENU:=Wireless Drivers
# AUTOLOAD:=$(call AutoLoad,30,bcm43xx-mac80211)
FILES:=$(PKG_BUILD_DIR)/bcm43xx-mac80211.$(LINUX_KMOD_SUFFIX)
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/bcm43xx/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) $(MAKE_CONFIGS) -C "$(LINUX_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
EXTRA_CFLAGS="$(BUILDFLAGS)" \
SUBDIRS="$(PKG_BUILD_DIR)" \
modules
endef
$(eval $(call KernelPackage,bcm43xx-mac80211))

View file

@ -0,0 +1 @@
source "drivers/net/wireless/mac80211/bcm43xx/Kconfig"

View file

@ -0,0 +1 @@
obj-$(CONFIG_BCM43XX_MAC80211) += bcm43xx/

View file

@ -0,0 +1,2 @@
This directory contains IEEE 802.11 wireless LAN drivers that are using
Devicescape IEEE 802.11 stack (net/mac80211).

View file

@ -0,0 +1,101 @@
config BCM43XX_MAC80211
tristate "Broadcom BCM43xx wireless support (mac80211 stack)"
depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
select SSB
select HW_RANDOM
---help---
This is an experimental driver for the Broadcom 43xx wireless chip,
found in the Apple Airport Extreme and various other devices.
config BCM43XX_MAC80211_PCI
bool "BCM43xx PCI device support"
depends on BCM43XX_MAC80211 && PCI
select SSB_PCIHOST
select SSB_DRIVER_PCICORE
default y
---help---
Broadcom 43xx PCI device support.
Say Y, if you have a BCM43xx device connected through the PCI bus.
Please note that most PC-CARD devices are (to the kernel) PCI devices,
too and not PCMCIA.
It's safe to select Y here, even if you don't have a BCM43xx PCI device.
config BCM43XX_MAC80211_PCMCIA
bool "BCM43xx PCMCIA device support"
depends on BCM43XX_MAC80211 && PCMCIA
select SSB_PCMCIAHOST
---help---
Broadcom 43xx PCMCIA device support.
Support for 16bit PCMCIA devices.
Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA
devices, but 32bit CardBUS devices. CardBUS devices are supported
by "BCM43xx PCI device support".
With this config option you can drive bcm43xx cards in
CompactFlash formfactor in a PCMCIA adaptor.
CF bcm43xx cards can sometimes be found in handheld PCs.
It's safe to select Y here, even if you don't have a BCM43xx PCMCIA device.
If unsure, say N.
config BCM43XX_MAC80211_DEBUG
bool "Broadcom BCM43xx debugging (RECOMMENDED)"
depends on BCM43XX_MAC80211
select SSB_DEBUG if !SSB_SILENT
default y
---help---
Broadcom 43xx debugging messages.
Say Y, because the driver is still very experimental and
this will help you get it running.
config BCM43XX_MAC80211_DMA
bool
depends on BCM43XX_MAC80211
config BCM43XX_MAC80211_PIO
bool
depends on BCM43XX_MAC80211
choice
prompt "BCM43xx data transfer mode"
depends on BCM43XX_MAC80211
default BCM43XX_MAC80211_DMA_AND_PIO_MODE
config BCM43XX_MAC80211_DMA_AND_PIO_MODE
bool "DMA + PIO"
select BCM43XX_MAC80211_DMA
select BCM43XX_MAC80211_PIO
---help---
Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
data transfer modes.
The actually used mode is selectable through the module
parameter "pio". If the module parameter is pio=0, DMA is used.
Otherwise PIO is used. DMA is default.
If unsure, choose this option.
config BCM43XX_MAC80211_DMA_MODE
bool "DMA (Direct Memory Access) only"
select BCM43XX_MAC80211_DMA
---help---
Only include Direct Memory Access (DMA).
This reduces the size of the driver module, by omitting the PIO code.
config BCM43XX_MAC80211_PIO_MODE
bool "PIO (Programmed I/O) only"
select BCM43XX_MAC80211_PIO
---help---
Only include Programmed I/O (PIO).
This reduces the size of the driver module, by omitting the DMA code.
Please note that PIO transfers are slow (compared to DMA).
Also note that not all devices of the 43xx series support PIO.
The 4306 (Apple Airport Extreme and others) supports PIO, while
the 4318 is known to _not_ support PIO.
Only use PIO, if DMA does not work for you.
endchoice

View file

@ -0,0 +1,18 @@
obj-$(CONFIG_BCM43XX_MAC80211) += bcm43xx-mac80211.o
bcm43xx-mac80211-obj-$(CONFIG_BCM43XX_MAC80211_PCMCIA) += bcm43xx_pcmcia.o
bcm43xx-mac80211-obj-$(CONFIG_BCM43XX_MAC80211_DEBUG) += bcm43xx_debugfs.o
bcm43xx-mac80211-obj-$(CONFIG_BCM43XX_MAC80211_DMA) += bcm43xx_dma.o
bcm43xx-mac80211-obj-$(CONFIG_BCM43XX_MAC80211_PIO) += bcm43xx_pio.o
bcm43xx-mac80211-objs := bcm43xx_main.o \
bcm43xx_tables.o \
bcm43xx_phy.o \
bcm43xx_power.o \
bcm43xx_sysfs.o \
bcm43xx_leds.o \
bcm43xx_xmit.o \
bcm43xx_lo.o \
$(bcm43xx-mac80211-obj-y)

View file

@ -0,0 +1,885 @@
#ifndef BCM43xx_H_
#define BCM43xx_H_
#include <linux/hw_random.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/stringify.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <asm/atomic.h>
#include <asm/io.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_driver_chipcommon.h>
#include <linux/wireless.h>
#include <net/mac80211.h>
#include "bcm43xx_debugfs.h"
#include "bcm43xx_leds.h"
#include "bcm43xx_lo.h"
#include "bcm43xx_phy.h"
#define PFX KBUILD_MODNAME ": "
#define BCM43xx_IRQWAIT_MAX_RETRIES 50
#define BCM43xx_IO_SIZE 8192
#define BCM43xx_RX_MAX_SSI 60
/* MMIO offsets */
#define BCM43xx_MMIO_DMA0_REASON 0x20
#define BCM43xx_MMIO_DMA0_IRQ_MASK 0x24
#define BCM43xx_MMIO_DMA1_REASON 0x28
#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x2C
#define BCM43xx_MMIO_DMA2_REASON 0x30
#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x34
#define BCM43xx_MMIO_DMA3_REASON 0x38
#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x3C
#define BCM43xx_MMIO_DMA4_REASON 0x40
#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x44
#define BCM43xx_MMIO_DMA5_REASON 0x48
#define BCM43xx_MMIO_DMA5_IRQ_MASK 0x4C
#define BCM43xx_MMIO_MACCTL 0x120
#define BCM43xx_MMIO_STATUS_BITFIELD 0x120//TODO replace all instances by MACCTL
#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124
#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128
#define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C
#define BCM43xx_MMIO_RAM_CONTROL 0x130
#define BCM43xx_MMIO_RAM_DATA 0x134
#define BCM43xx_MMIO_PS_STATUS 0x140
#define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158
#define BCM43xx_MMIO_SHM_CONTROL 0x160
#define BCM43xx_MMIO_SHM_DATA 0x164
#define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166
#define BCM43xx_MMIO_XMITSTAT_0 0x170
#define BCM43xx_MMIO_XMITSTAT_1 0x174
#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
/* 32-bit DMA */
#define BCM43xx_MMIO_DMA32_BASE0 0x200
#define BCM43xx_MMIO_DMA32_BASE1 0x220
#define BCM43xx_MMIO_DMA32_BASE2 0x240
#define BCM43xx_MMIO_DMA32_BASE3 0x260
#define BCM43xx_MMIO_DMA32_BASE4 0x280
#define BCM43xx_MMIO_DMA32_BASE5 0x2A0
/* 64-bit DMA */
#define BCM43xx_MMIO_DMA64_BASE0 0x200
#define BCM43xx_MMIO_DMA64_BASE1 0x240
#define BCM43xx_MMIO_DMA64_BASE2 0x280
#define BCM43xx_MMIO_DMA64_BASE3 0x2C0
#define BCM43xx_MMIO_DMA64_BASE4 0x300
#define BCM43xx_MMIO_DMA64_BASE5 0x340
/* PIO */
#define BCM43xx_MMIO_PIO1_BASE 0x300
#define BCM43xx_MMIO_PIO2_BASE 0x310
#define BCM43xx_MMIO_PIO3_BASE 0x320
#define BCM43xx_MMIO_PIO4_BASE 0x330
#define BCM43xx_MMIO_PHY_VER 0x3E0
#define BCM43xx_MMIO_PHY_RADIO 0x3E2
#define BCM43xx_MMIO_PHY0 0x3E6
#define BCM43xx_MMIO_ANTENNA 0x3E8
#define BCM43xx_MMIO_CHANNEL 0x3F0
#define BCM43xx_MMIO_CHANNEL_EXT 0x3F4
#define BCM43xx_MMIO_RADIO_CONTROL 0x3F6
#define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8
#define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA
#define BCM43xx_MMIO_PHY_CONTROL 0x3FC
#define BCM43xx_MMIO_PHY_DATA 0x3FE
#define BCM43xx_MMIO_MACFILTER_CONTROL 0x420
#define BCM43xx_MMIO_MACFILTER_DATA 0x422
#define BCM43xx_MMIO_RCMTA_COUNT 0x43C
#define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A
#define BCM43xx_MMIO_GPIO_CONTROL 0x49C
#define BCM43xx_MMIO_GPIO_MASK 0x49E
#define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */
#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */
#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */
#define BCM43xx_MMIO_RNG 0x65A
#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8
/* SPROM boardflags_lo values */
#define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
#define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
#define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */
#define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */
#define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */
#define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */
#define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */
#define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */
#define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */
#define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */
#define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */
#define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */
#define BCM43xx_BFL_EXTLNA 0x1000 /* has an external LNA */
#define BCM43xx_BFL_HGPA 0x2000 /* had high gain PA */
#define BCM43xx_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
#define BCM43xx_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
/* GPIO register offset, in both ChipCommon and PCI core. */
#define BCM43xx_GPIO_CONTROL 0x6c
/* SHM Routing */
enum {
BCM43xx_SHM_UCODE, /* Microcode memory */
BCM43xx_SHM_SHARED, /* Shared memory */
BCM43xx_SHM_SCRATCH, /* Scratch memory */
BCM43xx_SHM_HW, /* Internal hardware register */
BCM43xx_SHM_RCMTA, /* Receive match transmitter address (rev >= 5 only) */
};
/* SHM Routing modifiers */
#define BCM43xx_SHM_AUTOINC_R 0x0200 /* Auto-increment address on read */
#define BCM43xx_SHM_AUTOINC_W 0x0100 /* Auto-increment address on write */
#define BCM43xx_SHM_AUTOINC_RW (BCM43xx_SHM_AUTOINC_R | \
BCM43xx_SHM_AUTOINC_W)
/* Misc SHM_SHARED offsets */
#define BCM43xx_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */
#define BCM43xx_SHM_SH_PCTLWDPOS 0x0008
#define BCM43xx_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */
#define BCM43xx_SHM_SH_PHYVER 0x0050 /* PHY version */
#define BCM43xx_SHM_SH_PHYTYPE 0x0052 /* PHY type */
#define BCM43xx_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
#define BCM43xx_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
#define BCM43xx_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */
#define BCM43xx_SHM_SH_RADAR 0x0066 /* Radar register */
#define BCM43xx_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
#define BCM43xx_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
#define BCM43xx_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
#define BCM43xx_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */
#define BCM43xx_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* SHM_SHARED TX FIFO variables */
#define BCM43xx_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */
#define BCM43xx_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */
#define BCM43xx_SHM_SH_SIZE45 0x009C /* TX FIFO size for FIFO 4 and 5 */
#define BCM43xx_SHM_SH_SIZE67 0x009E /* TX FIFO size for FIFO 6 and 7 */
/* SHM_SHARED background noise */
#define BCM43xx_SHM_SH_JSSI0 0x0088 /* Measure JSSI 0 */
#define BCM43xx_SHM_SH_JSSI1 0x008A /* Measure JSSI 1 */
#define BCM43xx_SHM_SH_JSSIAUX 0x008C /* Measure JSSI AUX */
/* SHM_SHARED crypto engine */
#define BCM43xx_SHM_SH_DEFAULTIV 0x003C /* Default IV location */
#define BCM43xx_SHM_SH_NRRXTRANS 0x003E /* # of soft RX transmitter addresses (max 8) */
#define BCM43xx_SHM_SH_KTP 0x0056 /* Key table pointer */
#define BCM43xx_SHM_SH_TKIPTSCTTAK 0x0318
#define BCM43xx_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block (v4 firmware) */
#define BCM43xx_SHM_SH_PSM 0x05F4 /* PSM transmitter address match block (rev < 5) */
/* SHM_SHARED WME variables */
#define BCM43xx_SHM_SH_EDCFSTAT 0x000E /* EDCF status */
#define BCM43xx_SHM_SH_TXFCUR 0x0030 /* TXF current index */
#define BCM43xx_SHM_SH_EDCFQ 0x0240 /* EDCF Q info */
/* SHM_SHARED powersave mode related */
#define BCM43xx_SHM_SH_SLOTT 0x0010 /* Slot time */
#define BCM43xx_SHM_SH_DTIMPER 0x0012 /* DTIM period */
#define BCM43xx_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */
/* SHM_SHARED beacon variables */
#define BCM43xx_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
#define BCM43xx_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
#define BCM43xx_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
#define BCM43xx_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */
#define BCM43xx_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */
#define BCM43xx_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */
#define BCM43xx_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */
/* SHM_SHARED ACK/CTS control */
#define BCM43xx_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */
/* SHM_SHARED probe response variables */
#define BCM43xx_SHM_SH_PRSSID 0x0160 /* Probe Response SSID */
#define BCM43xx_SHM_SH_PRSSIDLEN 0x0048 /* Probe Response SSID length */
#define BCM43xx_SHM_SH_PRTLEN 0x004A /* Probe Response template length */
#define BCM43xx_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
#define BCM43xx_SHM_SH_PRPHYCTL 0x0188 /* Probe Response PHY TX control word */
/* SHM_SHARED rate tables */
#define BCM43xx_SHM_SH_OFDMDIRECT 0x01C0 /* Pointer to OFDM direct map */
#define BCM43xx_SHM_SH_OFDMBASIC 0x01E0 /* Pointer to OFDM basic rate map */
#define BCM43xx_SHM_SH_CCKDIRECT 0x0200 /* Pointer to CCK direct map */
#define BCM43xx_SHM_SH_CCKBASIC 0x0220 /* Pointer to CCK basic rate map */
/* SHM_SHARED microcode soft registers */
#define BCM43xx_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
#define BCM43xx_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
#define BCM43xx_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
#define BCM43xx_SHM_SH_UCODETIME 0x0006 /* Microcode time */
#define BCM43xx_SHM_SH_UCODESTAT 0x0040 /* Microcode debug status code */
#define BCM43xx_SHM_SH_UCODESTAT_INVALID 0
#define BCM43xx_SHM_SH_UCODESTAT_INIT 1
#define BCM43xx_SHM_SH_UCODESTAT_ACTIVE 2
#define BCM43xx_SHM_SH_UCODESTAT_SUSP 3 /* suspended */
#define BCM43xx_SHM_SH_UCODESTAT_SLEEP 4 /* asleep (PS) */
#define BCM43xx_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */
#define BCM43xx_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
#define BCM43xx_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
/* SHM_SCRATCH offsets */
#define BCM43xx_SHM_SC_MINCONT 0x0003 /* Minimum contention window */
#define BCM43xx_SHM_SC_MAXCONT 0x0004 /* Maximum contention window */
#define BCM43xx_SHM_SC_CURCONT 0x0005 /* Current contention window */
#define BCM43xx_SHM_SC_SRLIMIT 0x0006 /* Short retry count limit */
#define BCM43xx_SHM_SC_LRLIMIT 0x0007 /* Long retry count limit */
#define BCM43xx_SHM_SC_DTIMC 0x0008 /* Current DTIM count */
#define BCM43xx_SHM_SC_BTL0LEN 0x0015 /* Beacon 0 template length */
#define BCM43xx_SHM_SC_BTL1LEN 0x0016 /* Beacon 1 template length */
#define BCM43xx_SHM_SC_SCFB 0x0017 /* Short frame transmit count threshold for rate fallback */
#define BCM43xx_SHM_SC_LCFB 0x0018 /* Long frame transmit count threshold for rate fallback */
/* Hardware Radio Enable masks */
#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
/* HostFlags. See bcm43xx_hf_read/write() */
#define BCM43xx_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */
#define BCM43xx_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
#define BCM43xx_HF_RXPULLW 0x00000004 /* RX pullup workaround */
#define BCM43xx_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */
#define BCM43xx_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */
#define BCM43xx_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */
#define BCM43xx_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */
#define BCM43xx_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */
#define BCM43xx_HF_EDCF 0x00000100 /* on if WME and MAC suspended */
#define BCM43xx_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */
#define BCM43xx_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */
#define BCM43xx_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */
#define BCM43xx_HF_2060W 0x00001000 /* 2060 radio workaround */
#define BCM43xx_HF_RADARW 0x00002000 /* Radar workaround */
#define BCM43xx_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */
#define BCM43xx_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */
#define BCM43xx_HF_FWKUP 0x00020000 /* Fast wake-up ucode */
#define BCM43xx_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */
#define BCM43xx_HF_PCISCW 0x00080000 /* PCI slow clock workaround */
#define BCM43xx_HF_4318TSSI 0x00200000 /* 4318 TSSI */
#define BCM43xx_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */
#define BCM43xx_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */
#define BCM43xx_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */
#define BCM43xx_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */
#define BCM43xx_HF_SKCFPUP 0x04000000 /* Skip CFP update */
/* MacFilter offsets. */
#define BCM43xx_MACFILTER_SELF 0x0000
#define BCM43xx_MACFILTER_ASSOC 0x0003
/* PowerControl */
#define BCM43xx_PCTL_IN 0xB0
#define BCM43xx_PCTL_OUT 0xB4
#define BCM43xx_PCTL_OUTENABLE 0xB8
#define BCM43xx_PCTL_XTAL_POWERUP 0x40
#define BCM43xx_PCTL_PLL_POWERDOWN 0x80
/* PowerControl Clock Modes */
#define BCM43xx_PCTL_CLK_FAST 0x00
#define BCM43xx_PCTL_CLK_SLOW 0x01
#define BCM43xx_PCTL_CLK_DYNAMIC 0x02
#define BCM43xx_PCTL_FORCE_SLOW 0x0800
#define BCM43xx_PCTL_FORCE_PLL 0x1000
#define BCM43xx_PCTL_DYN_XTAL 0x2000
/* PHYVersioning */
#define BCM43xx_PHYTYPE_A 0x00
#define BCM43xx_PHYTYPE_B 0x01
#define BCM43xx_PHYTYPE_G 0x02
/* PHYRegisters */
#define BCM43xx_PHY_ILT_A_CTRL 0x0072
#define BCM43xx_PHY_ILT_A_DATA1 0x0073
#define BCM43xx_PHY_ILT_A_DATA2 0x0074
#define BCM43xx_PHY_G_LO_CONTROL 0x0810
#define BCM43xx_PHY_ILT_G_CTRL 0x0472
#define BCM43xx_PHY_ILT_G_DATA1 0x0473
#define BCM43xx_PHY_ILT_G_DATA2 0x0474
#define BCM43xx_PHY_A_PCTL 0x007B
#define BCM43xx_PHY_G_PCTL 0x0029
#define BCM43xx_PHY_A_CRS 0x0029
#define BCM43xx_PHY_RADIO_BITFIELD 0x0401
#define BCM43xx_PHY_G_CRS 0x0429
#define BCM43xx_PHY_NRSSILT_CTRL 0x0803
#define BCM43xx_PHY_NRSSILT_DATA 0x0804
/* RadioRegisters */
#define BCM43xx_RADIOCTL_ID 0x01
/* MAC Control bitfield */
#define BCM43xx_MACCTL_ENABLED 0x00000001 /* MAC Enabled */
#define BCM43xx_MACCTL_PSM_RUN 0x00000002 /* Run Microcode */
#define BCM43xx_MACCTL_PSM_JMP0 0x00000004 /* Microcode jump to 0 */
#define BCM43xx_MACCTL_SHM_ENABLED 0x00000100 /* SHM Enabled */
#define BCM43xx_MACCTL_SHM_UPPER 0x00000200 /* SHM Upper */
#define BCM43xx_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */
#define BCM43xx_MACCTL_PSM_DBG 0x00002000 /* Microcode debugging enabled */
#define BCM43xx_MACCTL_GPOUTSMSK 0x0000C000 /* GPOUT Select Mask */
#define BCM43xx_MACCTL_BE 0x00010000 /* Big Endian mode */
#define BCM43xx_MACCTL_INFRA 0x00020000 /* Infrastructure mode */
#define BCM43xx_MACCTL_AP 0x00040000 /* AccessPoint mode */
#define BCM43xx_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */
#define BCM43xx_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
#define BCM43xx_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */
#define BCM43xx_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
#define BCM43xx_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
#define BCM43xx_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
#define BCM43xx_MACCTL_HWPS 0x02000000 /* Hardware Power Saving */
#define BCM43xx_MACCTL_AWAKE 0x04000000 /* Device is awake */
#define BCM43xx_MACCTL_CLOSEDNET 0x08000000 /* Closed net (no SSID bcast) */
#define BCM43xx_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */
#define BCM43xx_MACCTL_DISCTXSTAT 0x20000000 /* Discard TX status */
#define BCM43xx_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */
#define BCM43xx_MACCTL_GMODE 0x80000000 /* G Mode */
/* StatusBitField *///FIXME rename these all
#define BCM43xx_SBF_MAC_ENABLED 0x00000001
#define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/
#define BCM43xx_SBF_CORE_READY 0x00000004
#define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/
#define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/
#define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/
#define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000
#define BCM43xx_SBF_MODE_NOTADHOC 0x00020000
#define BCM43xx_SBF_MODE_AP 0x00040000
#define BCM43xx_SBF_RADIOREG_LOCK 0x00080000
#define BCM43xx_SBF_MODE_MONITOR 0x00400000
#define BCM43xx_SBF_MODE_PROMISC 0x01000000
#define BCM43xx_SBF_PS1 0x02000000
#define BCM43xx_SBF_PS2 0x04000000
#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000
#define BCM43xx_SBF_TIME_UPDATE 0x10000000
#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/
/* 802.11 core specific TM State Low flags */
#define BCM43xx_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
#define BCM43xx_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */
#define BCM43xx_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */
#define BCM43xx_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
#define BCM43xx_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
/* 802.11 core specific TM State High flags */
#define BCM43xx_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5)*/
#define BCM43xx_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */
#define BCM43xx_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */
/* Generic-Interrupt reasons. */
#define BCM43xx_IRQ_MAC_SUSPENDED 0x00000001
#define BCM43xx_IRQ_BEACON 0x00000002
#define BCM43xx_IRQ_TBTT_INDI 0x00000004
#define BCM43xx_IRQ_BEACON_TX_OK 0x00000008
#define BCM43xx_IRQ_BEACON_CANCEL 0x00000010
#define BCM43xx_IRQ_ATIM_END 0x00000020
#define BCM43xx_IRQ_PMQ 0x00000040
#define BCM43xx_IRQ_PIO_WORKAROUND 0x00000100
#define BCM43xx_IRQ_MAC_TXERR 0x00000200
#define BCM43xx_IRQ_PHY_TXERR 0x00000800
#define BCM43xx_IRQ_PMEVENT 0x00001000
#define BCM43xx_IRQ_TIMER0 0x00002000
#define BCM43xx_IRQ_TIMER1 0x00004000
#define BCM43xx_IRQ_DMA 0x00008000
#define BCM43xx_IRQ_TXFIFO_FLUSH_OK 0x00010000
#define BCM43xx_IRQ_CCA_MEASURE_OK 0x00020000
#define BCM43xx_IRQ_NOISESAMPLE_OK 0x00040000
#define BCM43xx_IRQ_UCODE_DEBUG 0x08000000
#define BCM43xx_IRQ_RFKILL 0x10000000
#define BCM43xx_IRQ_TX_OK 0x20000000
#define BCM43xx_IRQ_PHY_G_CHANGED 0x40000000
#define BCM43xx_IRQ_TIMEOUT 0x80000000
#define BCM43xx_IRQ_ALL 0xFFFFFFFF
#define BCM43xx_IRQ_MASKTEMPLATE (BCM43xx_IRQ_MAC_SUSPENDED | \
BCM43xx_IRQ_BEACON | \
BCM43xx_IRQ_TBTT_INDI | \
BCM43xx_IRQ_ATIM_END | \
BCM43xx_IRQ_PMQ | \
BCM43xx_IRQ_MAC_TXERR | \
BCM43xx_IRQ_PHY_TXERR | \
BCM43xx_IRQ_DMA | \
BCM43xx_IRQ_TXFIFO_FLUSH_OK | \
BCM43xx_IRQ_NOISESAMPLE_OK | \
BCM43xx_IRQ_UCODE_DEBUG | \
BCM43xx_IRQ_RFKILL | \
BCM43xx_IRQ_TX_OK)
/* Device specific rate values.
* The actual values defined here are (rate_in_mbps * 2).
* Some code depends on this. Don't change it. */
#define BCM43xx_CCK_RATE_1MB 0x02
#define BCM43xx_CCK_RATE_2MB 0x04
#define BCM43xx_CCK_RATE_5MB 0x0B
#define BCM43xx_CCK_RATE_11MB 0x16
#define BCM43xx_OFDM_RATE_6MB 0x0C
#define BCM43xx_OFDM_RATE_9MB 0x12
#define BCM43xx_OFDM_RATE_12MB 0x18
#define BCM43xx_OFDM_RATE_18MB 0x24
#define BCM43xx_OFDM_RATE_24MB 0x30
#define BCM43xx_OFDM_RATE_36MB 0x48
#define BCM43xx_OFDM_RATE_48MB 0x60
#define BCM43xx_OFDM_RATE_54MB 0x6C
/* Convert a bcm43xx rate value to a rate in 100kbps */
#define BCM43xx_RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7
#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4
/* Max size of a security key */
#define BCM43xx_SEC_KEYSIZE 16
/* Security algorithms. */
enum {
BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
BCM43xx_SEC_ALGO_WEP40,
BCM43xx_SEC_ALGO_TKIP,
BCM43xx_SEC_ALGO_AES,
BCM43xx_SEC_ALGO_WEP104,
BCM43xx_SEC_ALGO_AES_LEGACY,
};
#ifdef assert
# undef assert
#endif
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
# define assert(expr) \
do { \
if (unlikely(!(expr))) { \
printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \
#expr, __FILE__, __LINE__, __FUNCTION__); \
} \
} while (0)
# define BCM43xx_DEBUG 1
#else
# define assert(expr) do { /* nothing */ } while (0)
# define BCM43xx_DEBUG 0
#endif
/* rate limited printk(). */
#ifdef printkl
# undef printkl
#endif
#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
/* rate limited printk() for debugging */
#ifdef dprintkl
# undef dprintkl
#endif
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
# define dprintkl printkl
#else
# define dprintkl(f, x...) do { /* nothing */ } while (0)
#endif
/* debugging printk() */
#ifdef dprintk
# undef dprintk
#endif
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
# define dprintk(f, x...) do { printk(f ,##x); } while (0)
#else
# define dprintk(f, x...) do { /* nothing */ } while (0)
#endif
struct net_device;
struct pci_dev;
struct bcm43xx_dmaring;
struct bcm43xx_pioqueue;
struct bcm43xx_initval {
u16 offset;
u16 size;
u32 value;
} __attribute__((__packed__));
#define BCM43xx_PHYMODE(phytype) (1 << (phytype))
#define BCM43xx_PHYMODE_A BCM43xx_PHYMODE(BCM43xx_PHYTYPE_A)
#define BCM43xx_PHYMODE_B BCM43xx_PHYMODE(BCM43xx_PHYTYPE_B)
#define BCM43xx_PHYMODE_G BCM43xx_PHYMODE(BCM43xx_PHYTYPE_G)
struct bcm43xx_phy {
/* Possible PHYMODEs on this PHY */
u8 possible_phymodes;
/* GMODE bit enabled? */
u8 gmode;
/* Possible ieee80211 subsystem hwmodes for this PHY.
* Which mode is selected, depends on thr GMODE enabled bit */
#define BCM43xx_MAX_PHYHWMODES 2
struct ieee80211_hw_mode hwmodes[BCM43xx_MAX_PHYHWMODES];
/* Analog Type */
u8 analog;
/* BCM43xx_PHYTYPE_ */
u8 type;
/* PHY revision number. */
u8 rev;
/* Radio versioning */
u16 radio_manuf; /* Radio manufacturer */
u16 radio_ver; /* Radio version */
u8 radio_rev; /* Radio revision */
u8 radio_on:1; /* Radio switched on/off */
u8 locked:1; /* Only used in bcm43xx_phy_{un}lock() */
u8 dyn_tssi_tbl:1; /* tssi2dbm is kmalloc()ed. */
/* ACI (adjacent channel interference) flags. */
u8 aci_enable:1;
u8 aci_wlan_automatic:1;
u8 aci_hw_rssi:1;
u16 minlowsig[2];
u16 minlowsigpos[2];
/* TSSI to dBm table in use */
const s8 *tssi2dbm;
/* Target idle TSSI */
int tgt_idle_tssi;
/* Current idle TSSI */
int cur_idle_tssi;
/* LocalOscillator control values. */
struct bcm43xx_txpower_lo_control *lo_control;
/* Values from bcm43xx_calc_loopback_gain() */
s16 max_lb_gain; /* Maximum Loopback gain in hdB */
s16 trsw_rx_gain; /* TRSW RX gain in hdB */
s16 lna_lod_gain; /* LNA lod */
s16 lna_gain; /* LNA */
s16 pga_gain; /* PGA */
/* PHY lock for core.rev < 3
* This lock is only used by bcm43xx_phy_{un}lock()
*/
spinlock_t lock;
/* Desired TX power level (in dBm).
* This is set by the user and adjusted in bcm43xx_phy_xmitpower(). */
u8 power_level;
/* TX Power control values. */
/* B/G PHY */
struct {
/* Current Radio Attenuation for TXpower recalculation. */
u16 rfatt;
/* Current Baseband Attenuation for TXpower recalculation. */
u16 bbatt;
/* Current TXpower control value for TXpower recalculation. */
u16 txctl1;
};
/* A PHY */
struct {
u16 txpwr_offset;
};
/* Current Interference Mitigation mode */
int interfmode;
/* Stack of saved values from the Interference Mitigation code.
* Each value in the stack is layed out as follows:
* bit 0-11: offset
* bit 12-15: register ID
* bit 16-32: value
* register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
*/
#define BCM43xx_INTERFSTACK_SIZE 26
u32 interfstack[BCM43xx_INTERFSTACK_SIZE];//FIXME: use a data structure
/* Saved values from the NRSSI Slope calculation */
s16 nrssi[2];
s32 nrssislope;
/* In memory nrssi lookup table. */
s8 nrssi_lt[64];
/* current channel */
u8 channel;
u16 lofcal;
u16 initval;//FIXME rename?
};
/* Data structures for DMA transmission, per 80211 core. */
struct bcm43xx_dma {
struct bcm43xx_dmaring *tx_ring0;
struct bcm43xx_dmaring *tx_ring1;
struct bcm43xx_dmaring *tx_ring2;
struct bcm43xx_dmaring *tx_ring3;
struct bcm43xx_dmaring *tx_ring4;
struct bcm43xx_dmaring *tx_ring5;
struct bcm43xx_dmaring *rx_ring0;
struct bcm43xx_dmaring *rx_ring3; /* only available on core.rev < 5 */
};
/* Data structures for PIO transmission, per 80211 core. */
struct bcm43xx_pio {
struct bcm43xx_pioqueue *queue0;
struct bcm43xx_pioqueue *queue1;
struct bcm43xx_pioqueue *queue2;
struct bcm43xx_pioqueue *queue3;
};
/* Context information for a noise calculation (Link Quality). */
struct bcm43xx_noise_calculation {
u8 channel_at_start;
u8 calculation_running:1;
u8 nr_samples;
s8 samples[8][4];
};
struct bcm43xx_stats {
u8 link_noise;
/* Store the last TX/RX times here for updating the leds. */
unsigned long last_tx;
unsigned long last_rx;
};
struct bcm43xx_key {
u8 enabled;
u8 algorithm;
u8 address[6];
};
struct bcm43xx_wldev;
/* Data structure for the WLAN parts (802.11 cores) of the bcm43xx chip. */
struct bcm43xx_wl {
/* Pointer to the active wireless device on this chip */
struct bcm43xx_wldev *current_dev;
/* Pointer to the ieee80211 hardware data structure */
struct ieee80211_hw *hw;
spinlock_t irq_lock;
struct mutex mutex;
spinlock_t leds_lock;
/* We can only have one operating interface (802.11 core)
* at a time. General information about this interface follows.
*/
/* Opaque ID of the operating interface (!= monitor
* interface) from the ieee80211 subsystem.
* Do not modify.
*/
int if_id;
/* MAC address. */
u8 *mac_addr;
/* Current BSSID (if any). */
u8 *bssid;
/* Interface type. (IEEE80211_IF_TYPE_XXX) */
int if_type;
/* Counter of active monitor interfaces. */
int monitor;
/* Is the card operating in AP, STA or IBSS mode? */
unsigned int operating:1;
/* Promisc mode active?
* Note that (monitor != 0) implies promisc.
*/
unsigned int promisc:1;
/* Stats about the wireless interface */
struct ieee80211_low_level_stats ieee_stats;
struct hwrng rng;
u8 rng_initialized;
char rng_name[30 + 1];
/* List of all wireless devices on this chip */
struct list_head devlist;
u8 nr_devs;
};
/* Pointers to the firmware data and meta information about it. */
struct bcm43xx_firmware {
/* Microcode */
const struct firmware *ucode;
/* PCM code */
const struct firmware *pcm;
/* Initial MMIO values 0 */
const struct firmware *initvals0;
/* Initial MMIO values 1 */
const struct firmware *initvals1;
/* Firmware revision */
u16 rev;
/* Firmware patchlevel */
u16 patch;
};
/* Device (802.11 core) initialization status. */
enum {
BCM43xx_STAT_UNINIT, /* Uninitialized. */
BCM43xx_STAT_INITIALIZING, /* bcm43xx_wireless_core_init() in progress. */
BCM43xx_STAT_INITIALIZED, /* Initialized. Note that this doesn't mean it's started. */
};
#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
#define bcm43xx_set_status(bcm, stat) do { \
atomic_set(&(bcm)->init_status, (stat)); \
smp_wmb(); \
} while (0)
/* XXX--- HOW LOCKING WORKS IN BCM43xx ---XXX
*
* You should always acquire both, wl->mutex and wl->irq_lock unless:
* - You don't need to acquire wl->irq_lock, if the interface is stopped.
* - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
* and packet TX path (and _ONLY_ there.)
*/
/* Data structure for one wireless device (802.11 core) */
struct bcm43xx_wldev {
struct ssb_device *dev;
struct bcm43xx_wl *wl;
/* Driver initialization status BCM43xx_STAT_*** */
atomic_t init_status;
/* Interface started? (bcm43xx_wireless_core_start()) */
u8 started;
u16 was_initialized:1, /* for suspend/resume. */
was_started:1, /* for suspend/resume. */
__using_pio:1, /* Internal, use bcm43xx_using_pio(). */
bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
short_preamble:1, /* TRUE, if short preamble is enabled. */
short_slot:1, /* TRUE, if short slot timing is enabled. */
radio_hw_enable:1; /* saved state of radio hardware enabled state */
/* PHY/Radio device. */
struct bcm43xx_phy phy;
union {
/* DMA engines. */
struct bcm43xx_dma dma;
/* PIO engines. */
struct bcm43xx_pio pio;
};
/* Various statistics about the physical device. */
struct bcm43xx_stats stats;
#define BCM43xx_NR_LEDS 4
struct bcm43xx_led leds[BCM43xx_NR_LEDS];
/* Reason code of the last interrupt. */
u32 irq_reason;
u32 dma_reason[6];
/* saved irq enable/disable state bitfield. */
u32 irq_savedstate;
/* Link Quality calculation context. */
struct bcm43xx_noise_calculation noisecalc;
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
int mac_suspended;
/* Interrupt Service Routine tasklet (bottom-half) */
struct tasklet_struct isr_tasklet;
/* Periodic tasks */
struct delayed_work periodic_work;
unsigned int periodic_state;
struct work_struct restart_work;
/* encryption/decryption */
u16 ktp; /* Key table pointer */
u8 max_nr_keys;
struct bcm43xx_key key[58];
/* Cached beacon template while uploading the template. */
struct sk_buff *cached_beacon;
/* Firmware data */
struct bcm43xx_firmware fw;
/* Devicelist in struct bcm43xx_wl (all 802.11 cores) */
struct list_head list;
/* Debugging stuff follows. */
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
struct bcm43xx_dfsentry *dfsentry;
#endif
};
static inline
struct bcm43xx_wl * hw_to_bcm43xx_wl(struct ieee80211_hw *hw)
{
return hw->priv;
}
/* Helper function, which returns a boolean.
* TRUE, if PIO is used; FALSE, if DMA is used.
*/
#if defined(CONFIG_BCM43XX_MAC80211_DMA) && defined(CONFIG_BCM43XX_MAC80211_PIO)
static inline
int bcm43xx_using_pio(struct bcm43xx_wldev *dev)
{
return dev->__using_pio;
}
#elif defined(CONFIG_BCM43XX_MAC80211_DMA)
static inline
int bcm43xx_using_pio(struct bcm43xx_wldev *dev)
{
return 0;
}
#elif defined(CONFIG_BCM43XX_MAC80211_PIO)
static inline
int bcm43xx_using_pio(struct bcm43xx_wldev *dev)
{
return 1;
}
#else
# error "Using neither DMA nor PIO? Confused..."
#endif
static inline
struct bcm43xx_wldev * dev_to_bcm43xx_wldev(struct device *dev)
{
struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
return ssb_get_drvdata(ssb_dev);
}
/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
static inline
int bcm43xx_is_mode(struct bcm43xx_wl *wl, int type)
{
if (type == IEEE80211_IF_TYPE_MNTR)
return !!(wl->monitor);
return (wl->operating &&
wl->if_type == type);
}
static inline
u16 bcm43xx_read16(struct bcm43xx_wldev *dev, u16 offset)
{
return ssb_read16(dev->dev, offset);
}
static inline
void bcm43xx_write16(struct bcm43xx_wldev *dev, u16 offset, u16 value)
{
ssb_write16(dev->dev, offset, value);
}
static inline
u32 bcm43xx_read32(struct bcm43xx_wldev *dev, u16 offset)
{
return ssb_read32(dev->dev, offset);
}
static inline
void bcm43xx_write32(struct bcm43xx_wldev *dev, u16 offset, u32 value)
{
ssb_write32(dev->dev, offset, value);
}
/** Limit a value between two limits */
#ifdef limit_value
# undef limit_value
#endif
#define limit_value(value, min, max) \
({ \
typeof(value) __value = (value); \
typeof(value) __min = (min); \
typeof(value) __max = (max); \
if (__value < __min) \
__value = __min; \
else if (__value > __max) \
__value = __max; \
__value; \
})
#endif /* BCM43xx_H_ */

View file

@ -0,0 +1,433 @@
/*
Broadcom BCM43xx wireless driver
debugfs driver debugging code
Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include "bcm43xx.h"
#include "bcm43xx_main.h"
#include "bcm43xx_debugfs.h"
#include "bcm43xx_dma.h"
#include "bcm43xx_pio.h"
#include "bcm43xx_xmit.h"
#define REALLY_BIG_BUFFER_SIZE (1024*256)
static struct bcm43xx_debugfs fs;
static char big_buffer[1024*256];
static DEFINE_MUTEX(big_buffer_mutex);
static ssize_t write_file_dummy(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return count;
}
static int open_file_generic(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x)
static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
const size_t len = ARRAY_SIZE(big_buffer);
char *buf = big_buffer;
size_t pos = 0;
ssize_t res;
mutex_lock(&big_buffer_mutex);
/* This is where the information is written to the "driver" file */
fappend(KBUILD_MODNAME " driver\n");
fappend("Compiled at: %s %s\n", __DATE__, __TIME__);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
mutex_unlock(&big_buffer_mutex);
return res;
}
static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct bcm43xx_wldev *dev = file->private_data;
const size_t len = ARRAY_SIZE(big_buffer);
char *buf = big_buffer;
size_t pos = 0;
ssize_t res;
unsigned long flags;
u64 tsf;
mutex_lock(&big_buffer_mutex);
mutex_lock(&dev->wl->mutex);
spin_lock_irqsave(&dev->wl->irq_lock, flags);
if (bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
}
bcm43xx_tsf_read(dev, &tsf);
fappend("0x%08x%08x\n",
(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
(unsigned int)(tsf & 0xFFFFFFFFULL));
out:
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
mutex_unlock(&dev->wl->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
mutex_unlock(&big_buffer_mutex);
return res;
}
static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct bcm43xx_wldev *dev = file->private_data;
char *buf = big_buffer;
ssize_t buf_size;
ssize_t res;
unsigned long flags;
u64 tsf;
mutex_lock(&big_buffer_mutex);
buf_size = min(count, ARRAY_SIZE(big_buffer) - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
res = -EFAULT;
goto out_unlock_bb;
}
mutex_lock(&dev->wl->mutex);
spin_lock_irqsave(&dev->wl->irq_lock, flags);
if (bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
goto out_unlock;
}
if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) {
printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n");
res = -EINVAL;
goto out_unlock;
}
bcm43xx_tsf_write(dev, tsf);
mmiowb();
res = buf_size;
out_unlock:
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
mutex_unlock(&dev->wl->mutex);
out_unlock_bb:
mutex_unlock(&big_buffer_mutex);
return res;
}
static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct bcm43xx_wldev *dev = file->private_data;
struct bcm43xx_dfsentry *e = dev->dfsentry;
struct bcm43xx_txstatus_log *log = &e->txstatlog;
unsigned long flags;
char *buf = log->printbuf;
const size_t len = ARRAY_SIZE(log->printbuf);
size_t pos = 0;
ssize_t res;
int i, idx;
struct bcm43xx_txstatus *stat;
mutex_lock(&big_buffer_mutex);
spin_lock_irqsave(&log->lock, flags);
if (!log->printing) {
log->printing = 1;
fappend("bcm43xx TX status reports:\n\n"
"index | cookie | seq | phy_stat | frame_count | "
"rts_count | supp_reason | pm_indicated | "
"intermediate | for_ampdu | acked\n"
"---\n");
i = log->end + 1;
idx = 0;
while (1) {
if (i == BCM43xx_NR_LOGGED_TXSTATUS)
i = 0;
stat = &(log->log[i]);
if (stat->cookie) {
fappend("%03d | "
"0x%04X | 0x%04X | 0x%02X | "
"0x%X | 0x%X | "
"%u | %u | "
"%u | %u | %u\n",
idx,
stat->cookie, stat->seq, stat->phy_stat,
stat->frame_count, stat->rts_count,
stat->supp_reason, stat->pm_indicated,
stat->intermediate, stat->for_ampdu,
stat->acked);
idx++;
}
if (i == log->end)
break;
i++;
}
log->buf_avail = pos;
}
memcpy(big_buffer, buf,
min(log->buf_avail, ARRAY_SIZE(big_buffer)));
spin_unlock_irqrestore(&log->lock, flags);
res = simple_read_from_buffer(userbuf, count, ppos,
big_buffer,
log->buf_avail);
if (*ppos == log->buf_avail) {
spin_lock_irqsave(&log->lock, flags);
log->printing = 0;
spin_unlock_irqrestore(&log->lock, flags);
}
mutex_unlock(&big_buffer_mutex);
return res;
}
static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct bcm43xx_wldev *dev = file->private_data;
char *buf = big_buffer;
ssize_t buf_size;
ssize_t res;
unsigned long flags;
mutex_lock(&big_buffer_mutex);
buf_size = min(count, ARRAY_SIZE(big_buffer) - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
res = -EFAULT;
goto out_unlock_bb;
}
mutex_lock(&dev->wl->mutex);
spin_lock_irqsave(&dev->wl->irq_lock, flags);
if (bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
goto out_unlock;
}
if (count > 0 && buf[0] == '1') {
bcm43xx_controller_restart(dev, "manually restarted");
res = count;
} else
res = -EINVAL;
out_unlock:
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
mutex_unlock(&dev->wl->mutex);
out_unlock_bb:
mutex_unlock(&big_buffer_mutex);
return res;
}
#undef fappend
static struct file_operations drvinfo_fops = {
.read = drvinfo_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
static struct file_operations tsf_fops = {
.read = tsf_read_file,
.write = tsf_write_file,
.open = open_file_generic,
};
static struct file_operations txstat_fops = {
.read = txstat_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
static struct file_operations restart_fops = {
.write = restart_write_file,
.open = open_file_generic,
};
void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev)
{
struct bcm43xx_dfsentry *e;
struct bcm43xx_txstatus_log *log;
char devdir[16];
assert(dev);
e = kzalloc(sizeof(*e), GFP_KERNEL);
if (!e) {
printk(KERN_ERR PFX "out of memory\n");
return;
}
e->dev = dev;
log = &e->txstatlog;
log->log = kcalloc(BCM43xx_NR_LOGGED_TXSTATUS,
sizeof(struct bcm43xx_txstatus),
GFP_KERNEL);
if (!log->log) {
printk(KERN_ERR PFX "debugfs txstatus log OOM\n");
kfree(e);
return;
}
log->end = -1;
spin_lock_init(&log->lock);
dev->dfsentry = e;
snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
e->subdir = debugfs_create_dir(devdir, fs.root);
e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir,
dev, &tsf_fops);
if (!e->dentry_tsf)
printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
dev, &txstat_fops);
if (!e->dentry_txstat)
printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
dev, &restart_fops);
if (!e->dentry_restart)
printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
}
void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *dev)
{
struct bcm43xx_dfsentry *e;
if (!dev)
return;
e = dev->dfsentry;
assert(e);
debugfs_remove(e->dentry_tsf);
debugfs_remove(e->dentry_txstat);
debugfs_remove(e->dentry_restart);
debugfs_remove(e->subdir);
kfree(e->txstatlog.log);
kfree(e);
}
void bcm43xx_debugfs_log_txstat(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status)
{
struct bcm43xx_dfsentry *e = dev->dfsentry;
struct bcm43xx_txstatus_log *log;
struct bcm43xx_txstatus *cur;
int i;
log = &e->txstatlog;
assert(irqs_disabled());
spin_lock(&log->lock);
i = log->end + 1;
if (i == BCM43xx_NR_LOGGED_TXSTATUS)
i = 0;
log->end = i;
cur = &(log->log[i]);
memcpy(cur, status, sizeof(*cur));
spin_unlock(&log->lock);
}
void bcm43xx_debugfs_init(void)
{
memset(&fs, 0, sizeof(fs));
fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
if (!fs.root)
printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n");
fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
if (!fs.dentry_driverinfo)
printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n");
}
void bcm43xx_debugfs_exit(void)
{
debugfs_remove(fs.dentry_driverinfo);
debugfs_remove(fs.root);
}
void bcm43xx_printk_dump(const char *data,
size_t size,
const char *description)
{
unsigned int i;
char c;
printk(KERN_INFO PFX "Data dump (%s, %lu bytes):",
description, (unsigned long)size);
for (i = 0; i < size; i++) {
c = data[i];
if (i % 8 == 0)
printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff);
else
printk("0x%02x, ", c & 0xff);
}
printk("\n");
}
void bcm43xx_printk_bitdump(const unsigned char *data,
size_t bytes, int msb_to_lsb,
const char *description)
{
unsigned int i;
int j;
const unsigned char *d;
printk(KERN_INFO PFX "*** Bitdump (%s, %lu bytes, %s) ***",
description, (unsigned long)bytes,
msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
for (i = 0; i < bytes; i++) {
d = data + i;
if (i % 8 == 0)
printk("\n" KERN_INFO PFX "0x%08x: ", i);
if (msb_to_lsb) {
for (j = 7; j >= 0; j--) {
if (*d & (1 << j))
printk("1");
else
printk("0");
}
} else {
for (j = 0; j < 8; j++) {
if (*d & (1 << j))
printk("1");
else
printk("0");
}
}
printk(" ");
}
printk("\n");
}

View file

@ -0,0 +1,110 @@
#ifndef BCM43xx_DEBUGFS_H_
#define BCM43xx_DEBUGFS_H_
struct bcm43xx_wldev;
struct bcm43xx_txstatus;
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
struct dentry;
#define BCM43xx_NR_LOGGED_TXSTATUS 100
struct bcm43xx_txstatus_log {
struct bcm43xx_txstatus *log;
int end;
int printing;
char printbuf[(BCM43xx_NR_LOGGED_TXSTATUS * 70) + 200];
size_t buf_avail;
spinlock_t lock;
};
struct bcm43xx_dfsentry {
struct dentry *subdir;
struct dentry *dentry_tsf;
struct dentry *dentry_txstat;
struct dentry *dentry_restart;
struct bcm43xx_wldev *dev;
struct bcm43xx_txstatus_log txstatlog;
};
struct bcm43xx_debugfs {
struct dentry *root;
struct dentry *dentry_driverinfo;
};
void bcm43xx_debugfs_init(void);
void bcm43xx_debugfs_exit(void);
void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev);
void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *dev);
void bcm43xx_debugfs_log_txstat(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status);
/* Debug helper: Dump binary data through printk. */
void bcm43xx_printk_dump(const char *data,
size_t size,
const char *description);
/* Debug helper: Dump bitwise binary data through printk. */
void bcm43xx_printk_bitdump(const unsigned char *data,
size_t bytes, int msb_to_lsb,
const char *description);
#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \
do { \
bcm43xx_printk_bitdump((const unsigned char *)(pointer), \
sizeof(*(pointer)), \
(msb_to_lsb), \
(description)); \
} while (0)
#else /* CONFIG_BCM43XX_MAC80211_DEBUG*/
static inline
void bcm43xx_debugfs_init(void) { }
static inline
void bcm43xx_debugfs_exit(void) { }
static inline
void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) { }
static inline
void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *dev) { }
static inline
void bcm43xx_debugfs_log_txstat(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status) { }
static inline
void bcm43xx_printk_dump(const char *data,
size_t size,
const char *description)
{
}
static inline
void bcm43xx_printk_bitdump(const unsigned char *data,
size_t bytes, int msb_to_lsb,
const char *description)
{
}
#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0)
#endif /* CONFIG_BCM43XX_MAC80211_DEBUG*/
/* Ugly helper macros to make incomplete code more verbose on runtime */
#ifdef TODO
# undef TODO
#endif
#define TODO() \
do { \
printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \
__FUNCTION__, __FILE__, __LINE__); \
} while (0)
#ifdef FIXME
# undef FIXME
#endif
#define FIXME() \
do { \
printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \
__FUNCTION__, __FILE__, __LINE__); \
} while (0)
#endif /* BCM43xx_DEBUGFS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,361 @@
#ifndef BCM43xx_DMA_H_
#define BCM43xx_DMA_H_
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/linkage.h>
#include <asm/atomic.h>
#include "bcm43xx.h"
/* DMA-Interrupt reasons. */
#define BCM43xx_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
| (1 << 14) | (1 << 15))
#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13)
#define BCM43xx_DMAIRQ_RX_DONE (1 << 16)
/*** 32-bit DMA Engine. ***/
/* 32-bit DMA controller registers. */
#define BCM43xx_DMA32_TXCTL 0x00
#define BCM43xx_DMA32_TXENABLE 0x00000001
#define BCM43xx_DMA32_TXSUSPEND 0x00000002
#define BCM43xx_DMA32_TXLOOPBACK 0x00000004
#define BCM43xx_DMA32_TXFLUSH 0x00000010
#define BCM43xx_DMA32_TXADDREXT_MASK 0x00030000
#define BCM43xx_DMA32_TXADDREXT_SHIFT 16
#define BCM43xx_DMA32_TXRING 0x04
#define BCM43xx_DMA32_TXINDEX 0x08
#define BCM43xx_DMA32_TXSTATUS 0x0C
#define BCM43xx_DMA32_TXDPTR 0x00000FFF
#define BCM43xx_DMA32_TXSTATE 0x0000F000
#define BCM43xx_DMA32_TXSTAT_DISABLED 0x00000000
#define BCM43xx_DMA32_TXSTAT_ACTIVE 0x00001000
#define BCM43xx_DMA32_TXSTAT_IDLEWAIT 0x00002000
#define BCM43xx_DMA32_TXSTAT_STOPPED 0x00003000
#define BCM43xx_DMA32_TXSTAT_SUSP 0x00004000
#define BCM43xx_DMA32_TXERROR 0x000F0000
#define BCM43xx_DMA32_TXERR_NOERR 0x00000000
#define BCM43xx_DMA32_TXERR_PROT 0x00010000
#define BCM43xx_DMA32_TXERR_UNDERRUN 0x00020000
#define BCM43xx_DMA32_TXERR_BUFREAD 0x00030000
#define BCM43xx_DMA32_TXERR_DESCREAD 0x00040000
#define BCM43xx_DMA32_TXACTIVE 0xFFF00000
#define BCM43xx_DMA32_RXCTL 0x10
#define BCM43xx_DMA32_RXENABLE 0x00000001
#define BCM43xx_DMA32_RXFROFF_MASK 0x000000FE
#define BCM43xx_DMA32_RXFROFF_SHIFT 1
#define BCM43xx_DMA32_RXDIRECTFIFO 0x00000100
#define BCM43xx_DMA32_RXADDREXT_MASK 0x00030000
#define BCM43xx_DMA32_RXADDREXT_SHIFT 16
#define BCM43xx_DMA32_RXRING 0x14
#define BCM43xx_DMA32_RXINDEX 0x18
#define BCM43xx_DMA32_RXSTATUS 0x1C
#define BCM43xx_DMA32_RXDPTR 0x00000FFF
#define BCM43xx_DMA32_RXSTATE 0x0000F000
#define BCM43xx_DMA32_RXSTAT_DISABLED 0x00000000
#define BCM43xx_DMA32_RXSTAT_ACTIVE 0x00001000
#define BCM43xx_DMA32_RXSTAT_IDLEWAIT 0x00002000
#define BCM43xx_DMA32_RXSTAT_STOPPED 0x00003000
#define BCM43xx_DMA32_RXERROR 0x000F0000
#define BCM43xx_DMA32_RXERR_NOERR 0x00000000
#define BCM43xx_DMA32_RXERR_PROT 0x00010000
#define BCM43xx_DMA32_RXERR_OVERFLOW 0x00020000
#define BCM43xx_DMA32_RXERR_BUFWRITE 0x00030000
#define BCM43xx_DMA32_RXERR_DESCREAD 0x00040000
#define BCM43xx_DMA32_RXACTIVE 0xFFF00000
/* 32-bit DMA descriptor. */
struct bcm43xx_dmadesc32 {
__le32 control;
__le32 address;
} __attribute__((__packed__));
#define BCM43xx_DMA32_DCTL_BYTECNT 0x00001FFF
#define BCM43xx_DMA32_DCTL_ADDREXT_MASK 0x00030000
#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT 16
#define BCM43xx_DMA32_DCTL_DTABLEEND 0x10000000
#define BCM43xx_DMA32_DCTL_IRQ 0x20000000
#define BCM43xx_DMA32_DCTL_FRAMEEND 0x40000000
#define BCM43xx_DMA32_DCTL_FRAMESTART 0x80000000
/*** 64-bit DMA Engine. ***/
/* 64-bit DMA controller registers. */
#define BCM43xx_DMA64_TXCTL 0x00
#define BCM43xx_DMA64_TXENABLE 0x00000001
#define BCM43xx_DMA64_TXSUSPEND 0x00000002
#define BCM43xx_DMA64_TXLOOPBACK 0x00000004
#define BCM43xx_DMA64_TXFLUSH 0x00000010
#define BCM43xx_DMA64_TXADDREXT_MASK 0x00030000
#define BCM43xx_DMA64_TXADDREXT_SHIFT 16
#define BCM43xx_DMA64_TXINDEX 0x04
#define BCM43xx_DMA64_TXRINGLO 0x08
#define BCM43xx_DMA64_TXRINGHI 0x0C
#define BCM43xx_DMA64_TXSTATUS 0x10
#define BCM43xx_DMA64_TXSTATDPTR 0x00001FFF
#define BCM43xx_DMA64_TXSTAT 0xF0000000
#define BCM43xx_DMA64_TXSTAT_DISABLED 0x00000000
#define BCM43xx_DMA64_TXSTAT_ACTIVE 0x10000000
#define BCM43xx_DMA64_TXSTAT_IDLEWAIT 0x20000000
#define BCM43xx_DMA64_TXSTAT_STOPPED 0x30000000
#define BCM43xx_DMA64_TXSTAT_SUSP 0x40000000
#define BCM43xx_DMA64_TXERROR 0x14
#define BCM43xx_DMA64_TXERRDPTR 0x0001FFFF
#define BCM43xx_DMA64_TXERR 0xF0000000
#define BCM43xx_DMA64_TXERR_NOERR 0x00000000
#define BCM43xx_DMA64_TXERR_PROT 0x10000000
#define BCM43xx_DMA64_TXERR_UNDERRUN 0x20000000
#define BCM43xx_DMA64_TXERR_TRANSFER 0x30000000
#define BCM43xx_DMA64_TXERR_DESCREAD 0x40000000
#define BCM43xx_DMA64_TXERR_CORE 0x50000000
#define BCM43xx_DMA64_RXCTL 0x20
#define BCM43xx_DMA64_RXENABLE 0x00000001
#define BCM43xx_DMA64_RXFROFF_MASK 0x000000FE
#define BCM43xx_DMA64_RXFROFF_SHIFT 1
#define BCM43xx_DMA64_RXDIRECTFIFO 0x00000100
#define BCM43xx_DMA64_RXADDREXT_MASK 0x00030000
#define BCM43xx_DMA64_RXADDREXT_SHIFT 16
#define BCM43xx_DMA64_RXINDEX 0x24
#define BCM43xx_DMA64_RXRINGLO 0x28
#define BCM43xx_DMA64_RXRINGHI 0x2C
#define BCM43xx_DMA64_RXSTATUS 0x30
#define BCM43xx_DMA64_RXSTATDPTR 0x00001FFF
#define BCM43xx_DMA64_RXSTAT 0xF0000000
#define BCM43xx_DMA64_RXSTAT_DISABLED 0x00000000
#define BCM43xx_DMA64_RXSTAT_ACTIVE 0x10000000
#define BCM43xx_DMA64_RXSTAT_IDLEWAIT 0x20000000
#define BCM43xx_DMA64_RXSTAT_STOPPED 0x30000000
#define BCM43xx_DMA64_RXSTAT_SUSP 0x40000000
#define BCM43xx_DMA64_RXERROR 0x34
#define BCM43xx_DMA64_RXERRDPTR 0x0001FFFF
#define BCM43xx_DMA64_RXERR 0xF0000000
#define BCM43xx_DMA64_RXERR_NOERR 0x00000000
#define BCM43xx_DMA64_RXERR_PROT 0x10000000
#define BCM43xx_DMA64_RXERR_UNDERRUN 0x20000000
#define BCM43xx_DMA64_RXERR_TRANSFER 0x30000000
#define BCM43xx_DMA64_RXERR_DESCREAD 0x40000000
#define BCM43xx_DMA64_RXERR_CORE 0x50000000
/* 64-bit DMA descriptor. */
struct bcm43xx_dmadesc64 {
__le32 control0;
__le32 control1;
__le32 address_low;
__le32 address_high;
} __attribute__((__packed__));
#define BCM43xx_DMA64_DCTL0_DTABLEEND 0x10000000
#define BCM43xx_DMA64_DCTL0_IRQ 0x20000000
#define BCM43xx_DMA64_DCTL0_FRAMEEND 0x40000000
#define BCM43xx_DMA64_DCTL0_FRAMESTART 0x80000000
#define BCM43xx_DMA64_DCTL1_BYTECNT 0x00001FFF
#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK 0x00030000
#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT 16
struct bcm43xx_dmadesc_generic {
union {
struct bcm43xx_dmadesc32 dma32;
struct bcm43xx_dmadesc64 dma64;
} __attribute__((__packed__));
} __attribute__((__packed__));
/* Misc DMA constants */
#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE
#define BCM43xx_DMA0_RX_FRAMEOFFSET 30
#define BCM43xx_DMA3_RX_FRAMEOFFSET 0
/* DMA engine tuning knobs */
#define BCM43xx_TXRING_SLOTS 128
#define BCM43xx_RXRING_SLOTS 64
#define BCM43xx_DMA0_RX_BUFFERSIZE (2304 + 100)
#define BCM43xx_DMA3_RX_BUFFERSIZE 16
#ifdef CONFIG_BCM43XX_MAC80211_DMA
struct sk_buff;
struct bcm43xx_private;
struct bcm43xx_txstatus;
struct bcm43xx_dmadesc_meta {
/* The kernel DMA-able buffer. */
struct sk_buff *skb;
/* DMA base bus-address of the descriptor buffer. */
dma_addr_t dmaaddr;
/* ieee80211 TX status. Only used once per 802.11 frag. */
u8 is_last_fragment;
struct ieee80211_tx_status txstat;
};
struct bcm43xx_dmaring;
/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
struct bcm43xx_dma_ops {
struct bcm43xx_dmadesc_generic * (*idx2desc)(struct bcm43xx_dmaring *ring,
int slot,
struct bcm43xx_dmadesc_meta **meta);
void (*fill_descriptor)(struct bcm43xx_dmaring *ring,
struct bcm43xx_dmadesc_generic *desc,
dma_addr_t dmaaddr, u16 bufsize,
int start, int end, int irq);
void (*poke_tx)(struct bcm43xx_dmaring *ring, int slot);
void (*tx_suspend)(struct bcm43xx_dmaring *ring);
void (*tx_resume)(struct bcm43xx_dmaring *ring);
int (*get_current_rxslot)(struct bcm43xx_dmaring *ring);
void (*set_current_rxslot)(struct bcm43xx_dmaring *ring, int slot);
};
struct bcm43xx_dmaring {
/* Lowlevel DMA ops. */
const struct bcm43xx_dma_ops *ops;
/* Kernel virtual base address of the ring memory. */
void *descbase;
/* Meta data about all descriptors. */
struct bcm43xx_dmadesc_meta *meta;
/* Cache of TX headers for each slot.
* This is to avoid an allocation on each TX.
* This is NULL for an RX ring.
*/
u8 *txhdr_cache;
/* (Unadjusted) DMA base bus-address of the ring memory. */
dma_addr_t dmabase;
/* Number of descriptor slots in the ring. */
int nr_slots;
/* Number of used descriptor slots. */
int used_slots;
/* Currently used slot in the ring. */
int current_slot;
/* Total number of packets sent. Statistics only. */
unsigned int nr_tx_packets;
/* Frameoffset in octets. */
u32 frameoffset;
/* Descriptor buffer size. */
u16 rx_buffersize;
/* The MMIO base register of the DMA controller. */
u16 mmio_base;
/* DMA controller index number (0-5). */
int index;
/* Boolean. Is this a TX ring? */
u8 tx;
/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
u8 dma64;
/* Boolean. Is this ring stopped at ieee80211 level? */
u8 stopped;
struct bcm43xx_wldev *dev;
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
/* Maximum number of used slots. */
int max_used_slots;
#endif /* CONFIG_BCM43XX_MAC80211_DEBUG*/
};
static inline
u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
u16 offset)
{
return bcm43xx_read32(ring->dev, ring->mmio_base + offset);
}
static inline
void bcm43xx_dma_write(struct bcm43xx_dmaring *ring,
u16 offset, u32 value)
{
bcm43xx_write32(ring->dev, ring->mmio_base + offset, value);
}
int bcm43xx_dma_init(struct bcm43xx_wldev *dev);
void bcm43xx_dma_free(struct bcm43xx_wldev *dev);
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_wldev *dev,
u16 dmacontroller_mmio_base,
int dma64);
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev,
u16 dmacontroller_mmio_base,
int dma64);
u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
struct ieee80211_tx_queue_stats *stats);
int bcm43xx_dma_tx(struct bcm43xx_wldev *dev,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl);
void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status);
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
#else /* CONFIG_BCM43XX_MAC80211_DMA */
static inline
int bcm43xx_dma_init(struct bcm43xx_wldev *dev)
{
return 0;
}
static inline
void bcm43xx_dma_free(struct bcm43xx_wldev *dev)
{
}
static inline
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_wldev *dev,
u16 dmacontroller_mmio_base,
int dma64)
{
return 0;
}
static inline
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev,
u16 dmacontroller_mmio_base,
int dma64)
{
return 0;
}
static inline
void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
}
static inline
int bcm43xx_dma_tx(struct bcm43xx_wldev *dev,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl)
{
return 0;
}
static inline
void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status)
{
}
static inline
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
{
}
static inline
void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
{
}
static inline
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
{
}
#endif /* CONFIG_BCM43XX_MAC80211_DMA */
#endif /* BCM43xx_DMA_H_ */

View file

@ -0,0 +1,300 @@
/*
Broadcom BCM43xx wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio <st3@riseup.net>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "bcm43xx_leds.h"
#include "bcm43xx.h"
#include "bcm43xx_main.h"
static void bcm43xx_led_changestate(struct bcm43xx_led *led)
{
struct bcm43xx_wldev *dev = led->dev;
const int index = bcm43xx_led_index(led);
const u16 mask = (1 << index);
u16 ledctl;
assert(index >= 0 && index < BCM43xx_NR_LEDS);
assert(led->blink_interval);
ledctl = bcm43xx_read16(dev, BCM43xx_MMIO_GPIO_CONTROL);
ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
bcm43xx_write16(dev, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
}
static void bcm43xx_led_blink(unsigned long d)
{
struct bcm43xx_led *led = (struct bcm43xx_led *)d;
struct bcm43xx_wldev *dev = led->dev;
unsigned long flags;
spin_lock_irqsave(&dev->wl->leds_lock, flags);
if (led->blink_interval) {
bcm43xx_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval);
}
spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
}
static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
unsigned long interval)
{
if (led->blink_interval)
return;
led->blink_interval = interval;
bcm43xx_led_changestate(led);
led->blink_timer.expires = jiffies + interval;
add_timer(&led->blink_timer);
}
static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
{
struct bcm43xx_wldev *dev = led->dev;
const int index = bcm43xx_led_index(led);
u16 ledctl;
if (!led->blink_interval)
return;
if (unlikely(sync))
del_timer_sync(&led->blink_timer);
else
del_timer(&led->blink_timer);
led->blink_interval = 0;
/* Make sure the LED is turned off. */
assert(index >= 0 && index < BCM43xx_NR_LEDS);
ledctl = bcm43xx_read16(dev, BCM43xx_MMIO_GPIO_CONTROL);
if (led->activelow)
ledctl |= (1 << index);
else
ledctl &= ~(1 << index);
bcm43xx_write16(dev, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
}
static void bcm43xx_led_init_hardcoded(struct bcm43xx_wldev *dev,
struct bcm43xx_led *led,
int led_index)
{
struct ssb_bus *bus = dev->dev->bus;
/* This function is called, if the behaviour (and activelow)
* information for a LED is missing in the SPROM.
* We hardcode the behaviour values for various devices here.
* Note that the BCM43xx_LED_TEST_XXX behaviour values can
* be used to figure out which led is mapped to which index.
*/
switch (led_index) {
case 0:
led->behaviour = BCM43xx_LED_ACTIVITY;
led->activelow = 1;
if (bus->board_vendor == PCI_VENDOR_ID_COMPAQ)
led->behaviour = BCM43xx_LED_RADIO_ALL;
break;
case 1:
led->behaviour = BCM43xx_LED_RADIO_B;
if (bus->board_vendor == PCI_VENDOR_ID_ASUSTEK)
led->behaviour = BCM43xx_LED_ASSOC;
break;
case 2:
led->behaviour = BCM43xx_LED_RADIO_A;
break;
case 3:
led->behaviour = BCM43xx_LED_OFF;
break;
default:
assert(0);
}
}
int bcm43xx_leds_init(struct bcm43xx_wldev *dev)
{
struct bcm43xx_led *led;
u8 sprom[4];
int i;
sprom[0] = dev->dev->bus->sprom.r1.gpio0;
sprom[1] = dev->dev->bus->sprom.r1.gpio1;
sprom[2] = dev->dev->bus->sprom.r1.gpio2;
sprom[3] = dev->dev->bus->sprom.r1.gpio3;
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(dev->leds[i]);
led->dev = dev;
setup_timer(&led->blink_timer,
bcm43xx_led_blink,
(unsigned long)led);
if (sprom[i] == 0xFF) {
bcm43xx_led_init_hardcoded(dev, led, i);
} else {
led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
}
}
return 0;
}
void bcm43xx_leds_exit(struct bcm43xx_wldev *dev)
{
struct bcm43xx_led *led;
int i;
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(dev->leds[i]);
bcm43xx_led_blink_stop(led, 1);
}
bcm43xx_leds_switch_all(dev, 0);
}
void bcm43xx_leds_update(struct bcm43xx_wldev *dev, int activity)
{
struct bcm43xx_led *led;
struct bcm43xx_phy *phy = &dev->phy;
const int transferring = (jiffies - dev->stats.last_tx) < BCM43xx_LED_XFER_THRES;
int i, turn_on;
unsigned long interval = 0;
u16 ledctl;
unsigned long flags;
spin_lock_irqsave(&dev->wl->leds_lock, flags);
ledctl = bcm43xx_read16(dev, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(dev->leds[i]);
turn_on = 0;
switch (led->behaviour) {
case BCM43xx_LED_INACTIVE:
continue;
case BCM43xx_LED_OFF:
break;
case BCM43xx_LED_ON:
turn_on = 1;
break;
case BCM43xx_LED_ACTIVITY:
turn_on = activity;
break;
case BCM43xx_LED_RADIO_ALL:
turn_on = phy->radio_on && bcm43xx_is_hw_radio_enabled(dev);
break;
case BCM43xx_LED_RADIO_A:
turn_on = (phy->radio_on && bcm43xx_is_hw_radio_enabled(dev)
&& phy->type == BCM43xx_PHYTYPE_A);
break;
case BCM43xx_LED_RADIO_B:
turn_on = (phy->radio_on && bcm43xx_is_hw_radio_enabled(dev) &&
(phy->type == BCM43xx_PHYTYPE_B ||
phy->type == BCM43xx_PHYTYPE_G));
break;
case BCM43xx_LED_MODE_BG:
if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(dev) &&
1/*FIXME: using G rates.*/)
turn_on = 1;
break;
case BCM43xx_LED_TRANSFER:
if (transferring)
bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
else
bcm43xx_led_blink_stop(led, 0);
continue;
case BCM43xx_LED_APTRANSFER:
if (bcm43xx_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
if (transferring) {
interval = BCM43xx_LEDBLINK_FAST;
turn_on = 1;
}
} else {
turn_on = 1;
if (0/*TODO: not assoc*/)
interval = BCM43xx_LEDBLINK_SLOW;
else if (transferring)
interval = BCM43xx_LEDBLINK_FAST;
else
turn_on = 0;
}
if (turn_on)
bcm43xx_led_blink_start(led, interval);
else
bcm43xx_led_blink_stop(led, 0);
continue;
case BCM43xx_LED_WEIRD:
//TODO
break;
case BCM43xx_LED_ASSOC:
if (1/*dev->softmac->associated*/)
turn_on = 1;
break;
#ifdef CONFIG_BCM43XX_DEBUG
case BCM43xx_LED_TEST_BLINKSLOW:
bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
continue;
case BCM43xx_LED_TEST_BLINKMEDIUM:
bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
continue;
case BCM43xx_LED_TEST_BLINKFAST:
bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
continue;
#endif /* CONFIG_BCM43XX_DEBUG */
default:
assert(0);
};
if (led->activelow)
turn_on = !turn_on;
if (turn_on)
ledctl |= (1 << i);
else
ledctl &= ~(1 << i);
}
bcm43xx_write16(dev, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
}
void bcm43xx_leds_switch_all(struct bcm43xx_wldev *dev, int on)
{
struct bcm43xx_led *led;
u16 ledctl;
int i;
int bit_on;
unsigned long flags;
spin_lock_irqsave(&dev->wl->leds_lock, flags);
ledctl = bcm43xx_read16(dev, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(dev->leds[i]);
if (led->behaviour == BCM43xx_LED_INACTIVE)
continue;
if (on)
bit_on = led->activelow ? 0 : 1;
else
bit_on = led->activelow ? 1 : 0;
if (bit_on)
ledctl |= (1 << i);
else
ledctl &= ~(1 << i);
}
bcm43xx_write16(dev, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
}

View file

@ -0,0 +1,56 @@
#ifndef BCM43xx_LEDS_H_
#define BCM43xx_LEDS_H_
#include <linux/types.h>
#include <linux/timer.h>
struct bcm43xx_led {
u8 behaviour:7;
u8 activelow:1;
struct bcm43xx_wldev *dev;
struct timer_list blink_timer;
unsigned long blink_interval;
};
#define bcm43xx_led_index(led) ((int)((led) - (led)->dev->leds))
/* Delay between state changes when blinking in jiffies */
#define BCM43xx_LEDBLINK_SLOW (HZ / 1)
#define BCM43xx_LEDBLINK_MEDIUM (HZ / 4)
#define BCM43xx_LEDBLINK_FAST (HZ / 8)
#define BCM43xx_LED_XFER_THRES (HZ / 100)
#define BCM43xx_LED_BEHAVIOUR 0x7F
#define BCM43xx_LED_ACTIVELOW 0x80
enum { /* LED behaviour values */
BCM43xx_LED_OFF,
BCM43xx_LED_ON,
BCM43xx_LED_ACTIVITY,
BCM43xx_LED_RADIO_ALL,
BCM43xx_LED_RADIO_A,
BCM43xx_LED_RADIO_B,
BCM43xx_LED_MODE_BG,
BCM43xx_LED_TRANSFER,
BCM43xx_LED_APTRANSFER,
BCM43xx_LED_WEIRD,//FIXME
BCM43xx_LED_ASSOC,
BCM43xx_LED_INACTIVE,
/* Behaviour values for testing.
* With these values it is easier to figure out
* the real behaviour of leds, in case the SPROM
* is missing information.
*/
BCM43xx_LED_TEST_BLINKSLOW,
BCM43xx_LED_TEST_BLINKMEDIUM,
BCM43xx_LED_TEST_BLINKFAST,
};
int bcm43xx_leds_init(struct bcm43xx_wldev *dev);
void bcm43xx_leds_exit(struct bcm43xx_wldev *dev);
void bcm43xx_leds_update(struct bcm43xx_wldev *dev, int activity);
void bcm43xx_leds_switch_all(struct bcm43xx_wldev *dev, int on);
#endif /* BCM43xx_LEDS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
#ifndef BCM43xx_LO_H_
#define BCM43xx_LO_H_
#include "bcm43xx_phy.h"
struct bcm43xx_wldev;
/* Local Oscillator control value-pair. */
struct bcm43xx_loctl {
/* Control values. */
s8 i;
s8 q;
/* "Used by hardware" flag. */
u8 used;
};
/* TX Power LO Control Array.
* Value-pairs to adjust the LocalOscillator are stored
* in this structure.
* There are two different set of values. One for "Flag is Set"
* and one for "Flag is Unset".
* By "Flag" the flag in struct bcm43xx_rfatt is meant.
* The Value arrays are two-dimensional. The first index
* is the baseband attenuation and the second index
* is the radio attenuation.
* Use bcm43xx_get_lo_g_ctl() to retrieve a value from the lists.
*/
struct bcm43xx_txpower_lo_control {
#define BCM43xx_NR_BB 9
#define BCM43xx_NR_RF 16
/* LO Control values, with PAD Mixer */
struct bcm43xx_loctl with_padmix[ BCM43xx_NR_BB ][ BCM43xx_NR_RF ];
/* LO Control values, without PAD Mixer */
struct bcm43xx_loctl no_padmix[ BCM43xx_NR_BB ][ BCM43xx_NR_RF ];
/* Flag to indicate a complete rebuild of the two tables above
* to the LO measuring code. */
u8 rebuild;
/* Lists of valid RF and BB attenuation values for this device. */
struct bcm43xx_rfatt_list rfatt_list;
struct bcm43xx_bbatt_list bbatt_list;
/* Current RF and BB attenuation and LO control values. */
struct bcm43xx_rfatt rfatt;
struct bcm43xx_bbatt bbatt;
/* Current TX Bias value */
u8 tx_bias;
/* Current TX Magnification Value (if used by the device) */
u8 tx_magn;
/* GPHY LO is measured. */
u8 lo_measured;
/* Saved device PowerVector */
u64 power_vector;
};
/* Measure the BPHY Local Oscillator. */
void bcm43xx_lo_b_measure(struct bcm43xx_wldev *dev);
/* Measure the BPHY/GPHY Local Oscillator. */
void bcm43xx_lo_g_measure(struct bcm43xx_wldev *dev);
/* Adjust the Local Oscillator to the saved attenuation
* and txctl values.
*/
void bcm43xx_lo_g_adjust(struct bcm43xx_wldev *dev);
/* Adjust to specific values. */
void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev,
u16 rfatt, u16 bbatt, u16 txctl1);
/* Returns the bcm43xx_lo_g_ctl corresponding to the current
* attenuation values.
*/
struct bcm43xx_loctl * bcm43xx_lo_g_ctl_current(struct bcm43xx_wldev *dev);
/* Mark all possible bcm43xx_lo_g_ctl as "unused" */
void bcm43xx_lo_g_ctl_mark_all_unused(struct bcm43xx_wldev *dev);
/* Mark the bcm43xx_lo_g_ctl corresponding to the current
* attenuation values as used.
*/
void bcm43xx_lo_g_ctl_mark_cur_used(struct bcm43xx_wldev *dev);
/* Get a reference to a LO Control value pair in the
* TX Power LO Control Array.
*/
struct bcm43xx_loctl * bcm43xx_get_lo_g_ctl(struct bcm43xx_wldev *dev,
const struct bcm43xx_rfatt *rfatt,
const struct bcm43xx_bbatt *bbatt);
#endif /* BCM43xx_LO_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,156 @@
/*
Broadcom BCM43xx wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio <st3@riseup.net>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
Some parts of the code in this file are derived from the ipw2200
driver Copyright(c) 2003 - 2004 Intel Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef BCM43xx_MAIN_H_
#define BCM43xx_MAIN_H_
#include "bcm43xx.h"
#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
/* Magic helper macro to pad structures. Ignore those above. It's magic. */
#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
static inline
u8 bcm43xx_freq_to_channel_a(int freq)
{
return ((freq - 5000) / 5);
}
static inline
u8 bcm43xx_freq_to_channel_bg(int freq)
{
u8 channel;
if (freq == 2484)
channel = 14;
else
channel = (freq - 2407) / 5;
return channel;
}
static inline
u8 bcm43xx_freq_to_channel(struct bcm43xx_wldev *dev,
int freq)
{
if (dev->phy.type == BCM43xx_PHYTYPE_A)
return bcm43xx_freq_to_channel_a(freq);
return bcm43xx_freq_to_channel_bg(freq);
}
/* Lightweight function to convert a channel number to a frequency (in Mhz). */
static inline
int bcm43xx_channel_to_freq_a(u8 channel)
{
return (5000 + (5 * channel));
}
static inline
int bcm43xx_channel_to_freq_bg(u8 channel)
{
int freq;
if (channel == 14)
freq = 2484;
else
freq = 2407 + (5 * channel);
return freq;
}
static inline
int bcm43xx_channel_to_freq(struct bcm43xx_wldev *dev,
u8 channel)
{
if (dev->phy.type == BCM43xx_PHYTYPE_A)
return bcm43xx_channel_to_freq_a(channel);
return bcm43xx_channel_to_freq_bg(channel);
}
static inline
int bcm43xx_is_cck_rate(int rate)
{
return (rate == BCM43xx_CCK_RATE_1MB ||
rate == BCM43xx_CCK_RATE_2MB ||
rate == BCM43xx_CCK_RATE_5MB ||
rate == BCM43xx_CCK_RATE_11MB);
}
static inline
int bcm43xx_is_ofdm_rate(int rate)
{
return !bcm43xx_is_cck_rate(rate);
}
static inline
int bcm43xx_is_hw_radio_enabled(struct bcm43xx_wldev *dev)
{
/* function to return state of hardware enable of radio
* returns 0 if radio disabled, 1 if radio enabled
*/
struct bcm43xx_phy *phy = &dev->phy;
if (phy->rev >= 3)
return ((bcm43xx_read32(dev, BCM43xx_MMIO_RADIO_HWENABLED_HI)
& BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
== 0) ? 1 : 0;
else
return ((bcm43xx_read16(dev, BCM43xx_MMIO_RADIO_HWENABLED_LO)
& BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
== 0) ? 0 : 1;
}
void bcm43xx_tsf_read(struct bcm43xx_wldev *dev, u64 *tsf);
void bcm43xx_tsf_write(struct bcm43xx_wldev *dev, u64 tsf);
u32 bcm43xx_shm_read32(struct bcm43xx_wldev *dev,
u16 routing, u16 offset);
u16 bcm43xx_shm_read16(struct bcm43xx_wldev *dev,
u16 routing, u16 offset);
void bcm43xx_shm_write32(struct bcm43xx_wldev *dev,
u16 routing, u16 offset,
u32 value);
void bcm43xx_shm_write16(struct bcm43xx_wldev *dev,
u16 routing, u16 offset,
u16 value);
u32 bcm43xx_hf_read(struct bcm43xx_wldev *dev);
void bcm43xx_hf_write(struct bcm43xx_wldev *dev, u32 value);
void bcm43xx_dummy_transmission(struct bcm43xx_wldev *dev);
void bcm43xx_wireless_core_reset(struct bcm43xx_wldev *dev, u32 flags);
void bcm43xx_mac_suspend(struct bcm43xx_wldev *dev);
void bcm43xx_mac_enable(struct bcm43xx_wldev *dev);
void bcm43xx_controller_restart(struct bcm43xx_wldev *dev, const char *reason);
#endif /* BCM43xx_MAIN_H_ */

View file

@ -0,0 +1,163 @@
/*
Broadcom BCM43xx wireless driver
Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <linux/ssb/ssb.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
static /*const*/ struct pcmcia_device_id bcm43xx_pcmcia_tbl[] = {
PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, bcm43xx_pcmcia_tbl);
#ifdef CONFIG_PM
static int bcm43xx_pcmcia_suspend(struct pcmcia_device *dev)
{
//TODO
return 0;
}
static int bcm43xx_pcmcia_resume(struct pcmcia_device *dev)
{
//TODO
return 0;
}
#else /* CONFIG_PM */
# define bcm43xx_pcmcia_suspend NULL
# define bcm43xx_pcmcia_resume NULL
#endif /* CONFIG_PM */
static void bcm43xx_pcmcia_fill_sprom(struct ssb_sprom *sprom)
{//TODO
}
static int __devinit bcm43xx_pcmcia_probe(struct pcmcia_device *dev)
{
struct ssb_bus *ssb;
win_req_t win;
memreq_t mem;
tuple_t tuple;
cisparse_t parse;
int err = -ENOMEM;
int res;
unsigned char buf[64];
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
if (!ssb)
goto out;
err = -ENODEV;
tuple.DesiredTuple = CISTPL_CONFIG;
tuple.Attributes = 0;
tuple.TupleData = buf;
tuple.TupleDataMax = sizeof(buf);
tuple.TupleOffset = 0;
res = pcmcia_get_first_tuple(dev, &tuple);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
res = pcmcia_get_tuple_data(dev, &tuple);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
res = pcmcia_parse_tuple(dev, &tuple, &parse);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
dev->conf.ConfigBase = parse.config.base;
dev->conf.Present = parse.config.rmask[0];
dev->io.BasePort2 = 0;
dev->io.NumPorts2 = 0;
dev->io.Attributes2 = 0;
win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
win.Base = 0;
win.Size = SSB_CORE_SIZE;
win.AccessSpeed = 1000;
res = pcmcia_request_window(&dev, &win, &dev->win);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
mem.CardOffset = 0;
mem.Page = 0;
res = pcmcia_map_mem_page(dev->win, &mem);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
res = pcmcia_request_configuration(dev, &dev->conf);
if (res != CS_SUCCESS)
goto err_disable;
err = ssb_bus_pcmciabus_register(ssb, dev, win.Base,
bcm43xx_pcmcia_fill_sprom);
dev->priv = ssb;
out:
return err;
err_disable:
pcmcia_disable_device(dev);
err_kfree_ssb:
kfree(ssb);
return err;
}
static void __devexit bcm43xx_pcmcia_remove(struct pcmcia_device *dev)
{
struct ssb_bus *ssb = dev->priv;
ssb_bus_unregister(ssb);
pcmcia_release_window(dev->win);
pcmcia_disable_device(dev);
kfree(ssb);
dev->priv = NULL;
}
static struct pcmcia_driver bcm43xx_pcmcia_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "bcm43xx-pcmcia",
},
.id_table = bcm43xx_pcmcia_tbl,
.probe = bcm43xx_pcmcia_probe,
.remove = bcm43xx_pcmcia_remove,
.suspend = bcm43xx_pcmcia_suspend,
.resume = bcm43xx_pcmcia_resume,
};
int bcm43xx_pcmcia_init(void)
{
return pcmcia_register_driver(&bcm43xx_pcmcia_driver);
}
void bcm43xx_pcmcia_exit(void)
{
pcmcia_unregister_driver(&bcm43xx_pcmcia_driver);
}

View file

@ -0,0 +1,22 @@
#ifndef BCM43xx_PCMCIA_H_
#define BCM43xx_PCMCIA_H_
#ifdef CONFIG_BCM43XX_MAC80211_PCMCIA
int bcm43xx_pcmcia_init(void);
void bcm43xx_pcmcia_exit(void);
#else /* CONFIG_BCM43XX_MAC80211_PCMCIA */
static inline
int bcm43xx_pcmcia_init(void)
{
return 0;
}
static inline
void bcm43xx_pcmcia_exit(void)
{
}
#endif /* CONFIG_BCM43XX_MAC80211_PCMCIA */
#endif /* BCM43xx_PCMCIA_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,309 @@
#ifndef BCM43xx_PHY_H_
#define BCM43xx_PHY_H_
#include <linux/types.h>
struct bcm43xx_wldev;
/*** PHY Registers ***/
/* Routing */
#define BCM43xx_PHYROUTE_OFDM_GPHY 0x400
#define BCM43xx_PHYROUTE_EXT_GPHY 0x800
/* Base registers. */
#define BCM43xx_PHY_BASE(reg) (reg)
/* OFDM (A) registers of a G-PHY */
#define BCM43xx_PHY_OFDM(reg) ((reg) | BCM43xx_PHYROUTE_OFDM_GPHY)
/* Extended G-PHY registers */
#define BCM43xx_PHY_EXTG(reg) ((reg) | BCM43xx_PHYROUTE_EXT_GPHY)
/* OFDM (A) PHY Registers */
#define BCM43xx_PHY_VERSION_OFDM BCM43xx_PHY_OFDM(0x00) /* Versioning register for A-PHY */
#define BCM43xx_PHY_BBANDCFG BCM43xx_PHY_OFDM(0x01) /* Baseband config */
#define BCM43xx_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
#define BCM43xx_PHY_BBANDCFG_RXANT_SHIFT 7
#define BCM43xx_PHY_PWRDOWN BCM43xx_PHY_OFDM(0x03) /* Powerdown */
#define BCM43xx_PHY_CRSTHRES1 BCM43xx_PHY_OFDM(0x06) /* CRS Threshold 1 */
#define BCM43xx_PHY_LNAHPFCTL BCM43xx_PHY_OFDM(0x1C) /* LNA/HPF control */
#define BCM43xx_PHY_ADIVRELATED BCM43xx_PHY_OFDM(0x27) /* FIXME rename */
#define BCM43xx_PHY_CRS0 BCM43xx_PHY_OFDM(0x29)
#define BCM43xx_PHY_ANTDWELL BCM43xx_PHY_OFDM(0x2B) /* Antenna dwell */
#define BCM43xx_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
#define BCM43xx_PHY_ENCORE BCM43xx_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
#define BCM43xx_PHY_ENCORE_EN 0x0200 /* Encore enable */
#define BCM43xx_PHY_LMS BCM43xx_PHY_OFDM(0x55)
#define BCM43xx_PHY_OFDM61 BCM43xx_PHY_OFDM(0x61) /* FIXME rename */
#define BCM43xx_PHY_OFDM61_10 0x0010 /* FIXME rename */
#define BCM43xx_PHY_IQBAL BCM43xx_PHY_OFDM(0x69) /* I/Q balance */
#define BCM43xx_PHY_OTABLECTL BCM43xx_PHY_OFDM(0x72) /* OFDM table control (see below) */
#define BCM43xx_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
#define BCM43xx_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
#define BCM43xx_PHY_OTABLENR_SHIFT 10
#define BCM43xx_PHY_OTABLEI BCM43xx_PHY_OFDM(0x73) /* OFDM table data I */
#define BCM43xx_PHY_OTABLEQ BCM43xx_PHY_OFDM(0x74) /* OFDM table data Q */
#define BCM43xx_PHY_HPWR_TSSICTL BCM43xx_PHY_OFDM(0x78) /* Hardware power TSSI control */
#define BCM43xx_PHY_NRSSITHRES BCM43xx_PHY_OFDM(0x8A) /* NRSSI threshold */
#define BCM43xx_PHY_ANTWRSETT BCM43xx_PHY_OFDM(0x8C) /* Antenna WR settle */
#define BCM43xx_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
#define BCM43xx_PHY_CLIPPWRDOWNT BCM43xx_PHY_OFDM(0x93) /* Clip powerdown threshold */
#define BCM43xx_PHY_OFDM9B BCM43xx_PHY_OFDM(0x9B) /* FIXME rename */
#define BCM43xx_PHY_N1P1GAIN BCM43xx_PHY_OFDM(0xA0)
#define BCM43xx_PHY_P1P2GAIN BCM43xx_PHY_OFDM(0xA1)
#define BCM43xx_PHY_N1N2GAIN BCM43xx_PHY_OFDM(0xA2)
#define BCM43xx_PHY_CLIPTHRES BCM43xx_PHY_OFDM(0xA3)
#define BCM43xx_PHY_CLIPN1P2THRES BCM43xx_PHY_OFDM(0xA4)
#define BCM43xx_PHY_DIVSRCHIDX BCM43xx_PHY_OFDM(0xA8) /* Divider search gain/index */
#define BCM43xx_PHY_CLIPP2THRES BCM43xx_PHY_OFDM(0xA9)
#define BCM43xx_PHY_CLIPP3THRES BCM43xx_PHY_OFDM(0xAA)
#define BCM43xx_PHY_DIVP1P2GAIN BCM43xx_PHY_OFDM(0xAB)
#define BCM43xx_PHY_DIVSRCHGAINBACK BCM43xx_PHY_OFDM(0xAD) /* Divider search gain back */
#define BCM43xx_PHY_DIVSRCHGAINCHNG BCM43xx_PHY_OFDM(0xAE) /* Divider search gain change */
#define BCM43xx_PHY_CRSTHRES1_R1 BCM43xx_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */
#define BCM43xx_PHY_CRSTHRES2_R1 BCM43xx_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */
#define BCM43xx_PHY_TSSIP_LTBASE BCM43xx_PHY_OFDM(0x380) /* TSSI power lookup table base */
#define BCM43xx_PHY_DC_LTBASE BCM43xx_PHY_OFDM(0x3A0) /* DC lookup table base */
#define BCM43xx_PHY_GAIN_LTBASE BCM43xx_PHY_OFDM(0x3C0) /* Gain lookup table base */
/* CCK (B) PHY Registers */
#define BCM43xx_PHY_VERSION_CCK BCM43xx_PHY_BASE(0x00) /* Versioning register for B-PHY */
#define BCM43xx_PHY_CCKBBANDCFG BCM43xx_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */
#define BCM43xx_PHY_PGACTL BCM43xx_PHY_BASE(0x15) /* PGA control */
#define BCM43xx_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
#define BCM43xx_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
#define BCM43xx_PHY_PGACTL_UNKNOWN 0xEFA0
#define BCM43xx_PHY_FBCTL1 BCM43xx_PHY_BASE(0x18) /* Frequency bandwidth control 1 */
#define BCM43xx_PHY_ITSSI BCM43xx_PHY_BASE(0x29) /* Idle TSSI */
#define BCM43xx_PHY_LO_LEAKAGE BCM43xx_PHY_BASE(0x2D) /* Measured LO leakage */
#define BCM43xx_PHY_ENERGY BCM43xx_PHY_BASE(0x33) /* Energy */
#define BCM43xx_PHY_SYNCCTL BCM43xx_PHY_BASE(0x35)
#define BCM43xx_PHY_FBCTL2 BCM43xx_PHY_BASE(0x38) /* Frequency bandwidth control 2 */
#define BCM43xx_PHY_DACCTL BCM43xx_PHY_BASE(0x60) /* DAC control */
#define BCM43xx_PHY_RCCALOVER BCM43xx_PHY_BASE(0x78) /* RC calibration override */
/* Extended G-PHY Registers */
#define BCM43xx_PHY_CLASSCTL BCM43xx_PHY_EXTG(0x02) /* Classify control */
#define BCM43xx_PHY_GTABCTL BCM43xx_PHY_EXTG(0x03) /* G-PHY table control (see below) */
#define BCM43xx_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
#define BCM43xx_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
#define BCM43xx_PHY_GTABNR_SHIFT 10
#define BCM43xx_PHY_GTABDATA BCM43xx_PHY_EXTG(0x04) /* G-PHY table data */
#define BCM43xx_PHY_LO_MASK BCM43xx_PHY_EXTG(0x0F) /* Local Oscillator control mask */
#define BCM43xx_PHY_LO_CTL BCM43xx_PHY_EXTG(0x10) /* Local Oscillator control */
#define BCM43xx_PHY_RFOVER BCM43xx_PHY_EXTG(0x11) /* RF override */
#define BCM43xx_PHY_RFOVERVAL BCM43xx_PHY_EXTG(0x12) /* RF override value */
#define BCM43xx_PHY_RFOVERVAL_EXTLNA 0x8000
#define BCM43xx_PHY_RFOVERVAL_LNA 0x7000
#define BCM43xx_PHY_RFOVERVAL_LNA_SHIFT 12
#define BCM43xx_PHY_RFOVERVAL_PGA 0x0F00
#define BCM43xx_PHY_RFOVERVAL_PGA_SHIFT 8
#define BCM43xx_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
#define BCM43xx_PHY_RFOVERVAL_TRSWRX 0x00E0
#define BCM43xx_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
#define BCM43xx_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
#define BCM43xx_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
#define BCM43xx_PHY_ANALOGOVER BCM43xx_PHY_EXTG(0x14) /* Analog override */
#define BCM43xx_PHY_ANALOGOVERVAL BCM43xx_PHY_EXTG(0x15) /* Analog override value */
/*** OFDM table numbers ***/
#define BCM43xx_OFDMTAB(number, offset) (((number) << BCM43xx_PHY_OTABLENR_SHIFT) | (offset))
#define BCM43xx_OFDMTAB_AGC1 BCM43xx_OFDMTAB(0x00, 0)
#define BCM43xx_OFDMTAB_GAIN0 BCM43xx_OFDMTAB(0x00, 0)
#define BCM43xx_OFDMTAB_GAINX BCM43xx_OFDMTAB(0x01, 0) //TODO rename
#define BCM43xx_OFDMTAB_GAIN1 BCM43xx_OFDMTAB(0x01, 4)
#define BCM43xx_OFDMTAB_AGC3 BCM43xx_OFDMTAB(0x02, 0)
#define BCM43xx_OFDMTAB_GAIN2 BCM43xx_OFDMTAB(0x02, 3)
#define BCM43xx_OFDMTAB_LNAHPFGAIN1 BCM43xx_OFDMTAB(0x03, 0)
#define BCM43xx_OFDMTAB_WRSSI BCM43xx_OFDMTAB(0x04, 0)
#define BCM43xx_OFDMTAB_LNAHPFGAIN2 BCM43xx_OFDMTAB(0x04, 0)
#define BCM43xx_OFDMTAB_NOISESCALE BCM43xx_OFDMTAB(0x05, 0)
#define BCM43xx_OFDMTAB_AGC2 BCM43xx_OFDMTAB(0x06, 0)
#define BCM43xx_OFDMTAB_ROTOR BCM43xx_OFDMTAB(0x08, 0)
#define BCM43xx_OFDMTAB_ADVRETARD BCM43xx_OFDMTAB(0x09, 0)
#define BCM43xx_OFDMTAB_DAC BCM43xx_OFDMTAB(0x0C, 0)
#define BCM43xx_OFDMTAB_DC BCM43xx_OFDMTAB(0x0E, 7)
#define BCM43xx_OFDMTAB_PWRDYN2 BCM43xx_OFDMTAB(0x0E, 12)
#define BCM43xx_OFDMTAB_LNAGAIN BCM43xx_OFDMTAB(0x0E, 13)
//TODO
#define BCM43xx_OFDMTAB_LPFGAIN BCM43xx_OFDMTAB(0x0F, 12)
#define BCM43xx_OFDMTAB_RSSI BCM43xx_OFDMTAB(0x10, 0)
//TODO
#define BCM43xx_OFDMTAB_AGC1_R1 BCM43xx_OFDMTAB(0x13, 0)
#define BCM43xx_OFDMTAB_GAINX_R1 BCM43xx_OFDMTAB(0x14, 0) //TODO rename
#define BCM43xx_OFDMTAB_MINSIGSQ BCM43xx_OFDMTAB(0x14, 1)
#define BCM43xx_OFDMTAB_AGC3_R1 BCM43xx_OFDMTAB(0x15, 0)
#define BCM43xx_OFDMTAB_WRSSI_R1 BCM43xx_OFDMTAB(0x15, 4)
#define BCM43xx_OFDMTAB_TSSI BCM43xx_OFDMTAB(0x15, 0)
#define BCM43xx_OFDMTAB_DACRFPABB BCM43xx_OFDMTAB(0x16, 0)
#define BCM43xx_OFDMTAB_DACOFF BCM43xx_OFDMTAB(0x17, 0)
#define BCM43xx_OFDMTAB_DCBIAS BCM43xx_OFDMTAB(0x18, 0)
u16 bcm43xx_ofdmtab_read16(struct bcm43xx_wldev *dev, u16 table, u16 offset);
void bcm43xx_ofdmtab_write16(struct bcm43xx_wldev *dev, u16 table,
u16 offset, u16 value);
u32 bcm43xx_ofdmtab_read32(struct bcm43xx_wldev *dev, u16 table, u16 offset);
void bcm43xx_ofdmtab_write32(struct bcm43xx_wldev *dev, u16 table,
u16 offset, u32 value);
/*** G-PHY table numbers */
#define BCM43xx_GTAB(number, offset) (((number) << BCM43xx_PHY_GTABNR_SHIFT) | (offset))
#define BCM43xx_GTAB_NRSSI BCM43xx_GTAB(0x00, 0)
#define BCM43xx_GTAB_TRFEMW BCM43xx_GTAB(0x0C, 0x120)
#define BCM43xx_GTAB_ORIGTR BCM43xx_GTAB(0x2E, 0x298)
u16 bcm43xx_gtab_read(struct bcm43xx_wldev *dev, u16 table, u16 offset); //TODO implement
void bcm43xx_gtab_write(struct bcm43xx_wldev *dev, u16 table,
u16 offset, u16 value); //TODO implement
#define BCM43xx_DEFAULT_CHANNEL_A 36
#define BCM43xx_DEFAULT_CHANNEL_BG 6
enum {
BCM43xx_ANTENNA0, /* Antenna 0 */
BCM43xx_ANTENNA1, /* Antenna 0 */
BCM43xx_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
BCM43xx_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
BCM43xx_ANTENNA_AUTO = BCM43xx_ANTENNA_AUTO0,
BCM43xx_ANTENNA_DEFAULT = BCM43xx_ANTENNA_AUTO,
};
enum {
BCM43xx_INTERFMODE_NONE,
BCM43xx_INTERFMODE_NONWLAN,
BCM43xx_INTERFMODE_MANUALWLAN,
BCM43xx_INTERFMODE_AUTOWLAN,
};
/* Masks for the different PHY versioning registers. */
#define BCM43xx_PHYVER_ANALOG 0xF000
#define BCM43xx_PHYVER_ANALOG_SHIFT 12
#define BCM43xx_PHYVER_TYPE 0x0F00
#define BCM43xx_PHYVER_TYPE_SHIFT 8
#define BCM43xx_PHYVER_VERSION 0x00FF
void bcm43xx_raw_phy_lock(struct bcm43xx_wldev *dev);
#define bcm43xx_phy_lock(dev, flags) \
do { \
local_irq_save(flags); \
bcm43xx_raw_phy_lock(dev); \
} while (0)
void bcm43xx_raw_phy_unlock(struct bcm43xx_wldev *dev);
#define bcm43xx_phy_unlock(dev, flags) \
do { \
bcm43xx_raw_phy_unlock(dev); \
local_irq_restore(flags); \
} while (0)
u16 bcm43xx_phy_read(struct bcm43xx_wldev *dev, u16 offset);
void bcm43xx_phy_write(struct bcm43xx_wldev *dev, u16 offset, u16 val);
int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_wldev *dev);
void bcm43xx_phy_early_init(struct bcm43xx_wldev *dev);
int bcm43xx_phy_init(struct bcm43xx_wldev *dev);
void bcm43xx_set_rx_antenna(struct bcm43xx_wldev *dev, int antenna);
void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev);
void bcm43xx_gphy_dc_lt_init(struct bcm43xx_wldev *dev);
/* Returns the boolean whether the board has HardwarePowerControl */
#define has_hardware_pctl(phy) \
(((phy)->type == BCM43xx_PHYTYPE_A && (phy)->rev >= 5) || \
((phy)->type == BCM43xx_PHYTYPE_G && (phy)->rev >= 6))
/* Returns the boolean whether "TX Magnification" is enabled. */
#define has_tx_magnification(phy) \
(((phy)->rev >= 2) && \
((phy)->radio_ver == 0x2050) && \
((phy)->radio_rev == 8))
/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
(((phy)->rev > 1) || ((phy)->gmode))
/* Radio Attenuation (RF Attenuation) */
struct bcm43xx_rfatt {
u8 att; /* Attenuation value */
u8 with_padmix; /* Flag, PAD Mixer enabled. */
};
struct bcm43xx_rfatt_list {
/* Attenuation values list */
const struct bcm43xx_rfatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Baseband Attenuation */
struct bcm43xx_bbatt {
u8 att; /* Attenuation value */
};
struct bcm43xx_bbatt_list {
/* Attenuation values list */
const struct bcm43xx_bbatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Write BasebandAttenuation value to the device. */
void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_wldev *dev,
u16 baseband_attenuation);
extern const u8 bcm43xx_radio_channel_codes_bg[];
void bcm43xx_radio_lock(struct bcm43xx_wldev *dev);
void bcm43xx_radio_unlock(struct bcm43xx_wldev *dev);
u16 bcm43xx_radio_read16(struct bcm43xx_wldev *dev, u16 offset);
void bcm43xx_radio_write16(struct bcm43xx_wldev *dev, u16 offset, u16 val);
u16 bcm43xx_radio_init2050(struct bcm43xx_wldev *dev);
void bcm43xx_radio_init2060(struct bcm43xx_wldev *dev);
void bcm43xx_radio_turn_on(struct bcm43xx_wldev *dev);
void bcm43xx_radio_turn_off(struct bcm43xx_wldev *dev);
int bcm43xx_radio_selectchannel(struct bcm43xx_wldev *dev, u8 channel,
int synthetic_pu_workaround);
void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower);
/* Set the txpower on device. If the values are < 0, use the saved ones. */
void bcm43xx_radio_set_txpower_bg(struct bcm43xx_wldev *dev,
s16 baseband_attenuation,
s16 radio_attenuation,
s16 txctl1);
u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_wldev *dev);
u16 bcm43xx_default_radio_attenuation(struct bcm43xx_wldev *dev);
u16 bcm43xx_default_txctl1(struct bcm43xx_wldev *dev);
u8 bcm43xx_radio_aci_detect(struct bcm43xx_wldev *dev, u8 channel);
u8 bcm43xx_radio_aci_scan(struct bcm43xx_wldev *dev);
int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_wldev *dev, int mode);
void bcm43xx_calc_nrssi_slope(struct bcm43xx_wldev *dev);
void bcm43xx_calc_nrssi_threshold(struct bcm43xx_wldev *dev);
s16 bcm43xx_nrssi_hw_read(struct bcm43xx_wldev *dev, u16 offset);
void bcm43xx_nrssi_hw_write(struct bcm43xx_wldev *dev, u16 offset, s16 val);
void bcm43xx_nrssi_hw_update(struct bcm43xx_wldev *dev, u16 val);
void bcm43xx_nrssi_mem_update(struct bcm43xx_wldev *dev);
void bcm43xx_radio_set_tx_iq(struct bcm43xx_wldev *dev);
u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_wldev *dev);
#endif /* BCM43xx_PHY_H_ */

View file

@ -0,0 +1,671 @@
/*
Broadcom BCM43xx wireless driver
PIO Transmission
Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "bcm43xx.h"
#include "bcm43xx_pio.h"
#include "bcm43xx_main.h"
#include "bcm43xx_xmit.h"
#include "bcm43xx_power.h"
#include <linux/delay.h>
static void tx_start(struct bcm43xx_pioqueue *queue)
{
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
BCM43xx_PIO_TXCTL_INIT);
}
static void tx_octet(struct bcm43xx_pioqueue *queue,
u8 octet)
{
if (queue->need_workarounds) {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
octet);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
BCM43xx_PIO_TXCTL_WRITELO);
} else {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
BCM43xx_PIO_TXCTL_WRITELO);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
octet);
}
}
static u16 tx_get_next_word(const u8 *txhdr,
const u8 *packet,
size_t txhdr_size,
unsigned int *pos)
{
const u8 *source;
unsigned int i = *pos;
u16 ret;
if (i < txhdr_size) {
source = txhdr;
} else {
source = packet;
i -= txhdr_size;
}
ret = le16_to_cpu( *((u16 *)(source + i)) );
*pos += 2;
return ret;
}
static void tx_data(struct bcm43xx_pioqueue *queue,
u8 *txhdr,
const u8 *packet,
unsigned int octets)
{
u16 data;
unsigned int i = 0;
if (queue->need_workarounds) {
data = tx_get_next_word(txhdr, packet,
sizeof(struct bcm43xx_txhdr_fw4), &i);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
}
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
BCM43xx_PIO_TXCTL_WRITELO |
BCM43xx_PIO_TXCTL_WRITEHI);
while (i < octets - 1) {
data = tx_get_next_word(txhdr, packet,
sizeof(struct bcm43xx_txhdr_fw4), &i);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
}
if (octets % 2)
tx_octet(queue, packet[octets - sizeof(struct bcm43xx_txhdr_fw4) - 1]);
}
static void tx_complete(struct bcm43xx_pioqueue *queue,
struct sk_buff *skb)
{
if (queue->need_workarounds) {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
skb->data[skb->len - 1]);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
BCM43xx_PIO_TXCTL_WRITELO |
BCM43xx_PIO_TXCTL_COMPLETE);
} else {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
BCM43xx_PIO_TXCTL_COMPLETE);
}
}
static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
struct bcm43xx_pio_txpacket *packet)
{
u16 cookie = 0x0000;
int packetindex;
/* We use the upper 4 bits for the PIO
* controller ID and the lower 12 bits
* for the packet index (in the cache).
*/
switch (queue->mmio_base) {
case BCM43xx_MMIO_PIO1_BASE:
break;
case BCM43xx_MMIO_PIO2_BASE:
cookie = 0x1000;
break;
case BCM43xx_MMIO_PIO3_BASE:
cookie = 0x2000;
break;
case BCM43xx_MMIO_PIO4_BASE:
cookie = 0x3000;
break;
default:
assert(0);
}
packetindex = pio_txpacket_getindex(packet);
assert(((u16)packetindex & 0xF000) == 0x0000);
cookie |= (u16)packetindex;
return cookie;
}
static
struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_wldev *dev,
u16 cookie,
struct bcm43xx_pio_txpacket **packet)
{
struct bcm43xx_pio *pio = &dev->pio;
struct bcm43xx_pioqueue *queue = NULL;
int packetindex;
switch (cookie & 0xF000) {
case 0x0000:
queue = pio->queue0;
break;
case 0x1000:
queue = pio->queue1;
break;
case 0x2000:
queue = pio->queue2;
break;
case 0x3000:
queue = pio->queue3;
break;
default:
assert(0);
}
packetindex = (cookie & 0x0FFF);
assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS);
*packet = &(queue->tx_packets_cache[packetindex]);
return queue;
}
union txhdr_union {
struct bcm43xx_txhdr_fw4 txhdr_fw4;
};
static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
struct sk_buff *skb,
struct bcm43xx_pio_txpacket *packet,
size_t txhdr_size)
{
union txhdr_union txhdr_data;
u8 *txhdr = NULL;
unsigned int octets;
txhdr = (u8 *)(&txhdr_data.txhdr_fw4);
assert(skb_shinfo(skb)->nr_frags == 0);
bcm43xx_generate_txhdr(queue->dev,
txhdr, skb->data, skb->len,
&packet->txstat.control,
generate_cookie(queue, packet));
tx_start(queue);
octets = skb->len + txhdr_size;
if (queue->need_workarounds)
octets--;
tx_data(queue, txhdr, (u8 *)skb->data, octets);
tx_complete(queue, skb);
}
static void free_txpacket(struct bcm43xx_pio_txpacket *packet,
int irq_context)
{
struct bcm43xx_pioqueue *queue = packet->queue;
if (packet->skb) {
if (irq_context)
dev_kfree_skb_irq(packet->skb);
else
dev_kfree_skb(packet->skb);
}
list_move(&packet->list, &queue->txfree);
queue->nr_txfree++;
}
static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
{
struct bcm43xx_pioqueue *queue = packet->queue;
struct sk_buff *skb = packet->skb;
u16 octets;
octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr_fw4);
if (queue->tx_devq_size < octets) {
printkl(KERN_WARNING PFX "PIO queue too small. "
"Dropping packet.\n");
/* Drop it silently (return success) */
free_txpacket(packet, 1);
return 0;
}
assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS);
assert(queue->tx_devq_used <= queue->tx_devq_size);
/* Check if there is sufficient free space on the device
* TX queue. If not, return and let the TX tasklet
* retry later.
*/
if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS)
return -EBUSY;
if (queue->tx_devq_used + octets > queue->tx_devq_size)
return -EBUSY;
/* Now poke the device. */
pio_tx_write_fragment(queue, skb, packet, sizeof(struct bcm43xx_txhdr_fw4));
/* Account for the packet size.
* (We must not overflow the device TX queue)
*/
queue->tx_devq_packets++;
queue->tx_devq_used += octets;
/* Transmission started, everything ok, move the
* packet to the txrunning list.
*/
list_move_tail(&packet->list, &queue->txrunning);
return 0;
}
static void tx_tasklet(unsigned long d)
{
struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d;
struct bcm43xx_wldev *dev = queue->dev;
unsigned long flags;
struct bcm43xx_pio_txpacket *packet, *tmp_packet;
int err;
u16 txctl;
spin_lock_irqsave(&dev->wl->irq_lock, flags);
if (queue->tx_frozen)
goto out_unlock;
txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
goto out_unlock;
list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
/* Try to transmit the packet. This can fail, if
* the device queue is full. In case of failure, the
* packet is left in the txqueue.
* If transmission succeed, the packet is moved to txrunning.
* If it is impossible to transmit the packet, it
* is dropped.
*/
err = pio_tx_packet(packet);
if (err)
break;
}
out_unlock:
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
}
static void setup_txqueues(struct bcm43xx_pioqueue *queue)
{
struct bcm43xx_pio_txpacket *packet;
int i;
queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS;
for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) {
packet = &(queue->tx_packets_cache[i]);
packet->queue = queue;
INIT_LIST_HEAD(&packet->list);
list_add(&packet->list, &queue->txfree);
}
}
static
struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_wldev *dev,
u16 pio_mmio_base)
{
struct bcm43xx_pioqueue *queue;
u32 value;
u16 qsize;
queue = kzalloc(sizeof(*queue), GFP_KERNEL);
if (!queue)
goto out;
queue->dev = dev;
queue->mmio_base = pio_mmio_base;
queue->need_workarounds = (dev->dev->id.revision < 3);
INIT_LIST_HEAD(&queue->txfree);
INIT_LIST_HEAD(&queue->txqueue);
INIT_LIST_HEAD(&queue->txrunning);
tasklet_init(&queue->txtask, tx_tasklet,
(unsigned long)queue);
value = bcm43xx_read32(dev, BCM43xx_MMIO_STATUS_BITFIELD);
value &= ~BCM43xx_SBF_XFER_REG_BYTESWAP;
bcm43xx_write32(dev, BCM43xx_MMIO_STATUS_BITFIELD, value);
qsize = bcm43xx_read16(dev, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
if (qsize == 0) {
printk(KERN_ERR PFX "ERROR: This card does not support PIO "
"operation mode. Please use DMA mode "
"(module parameter pio=0).\n");
goto err_freequeue;
}
if (qsize <= BCM43xx_PIO_TXQADJUST) {
printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n",
qsize);
goto err_freequeue;
}
qsize -= BCM43xx_PIO_TXQADJUST;
queue->tx_devq_size = qsize;
setup_txqueues(queue);
out:
return queue;
err_freequeue:
kfree(queue);
queue = NULL;
goto out;
}
static void cancel_transfers(struct bcm43xx_pioqueue *queue)
{
struct bcm43xx_pio_txpacket *packet, *tmp_packet;
tasklet_disable(&queue->txtask);
list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
free_txpacket(packet, 0);
list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
free_txpacket(packet, 0);
}
static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue)
{
if (!queue)
return;
cancel_transfers(queue);
kfree(queue);
}
void bcm43xx_pio_free(struct bcm43xx_wldev *dev)
{
struct bcm43xx_pio *pio;
if (!bcm43xx_using_pio(dev))
return;
pio = &dev->pio;
bcm43xx_destroy_pioqueue(pio->queue3);
pio->queue3 = NULL;
bcm43xx_destroy_pioqueue(pio->queue2);
pio->queue2 = NULL;
bcm43xx_destroy_pioqueue(pio->queue1);
pio->queue1 = NULL;
bcm43xx_destroy_pioqueue(pio->queue0);
pio->queue0 = NULL;
}
int bcm43xx_pio_init(struct bcm43xx_wldev *dev)
{
struct bcm43xx_pio *pio = &dev->pio;
struct bcm43xx_pioqueue *queue;
int err = -ENOMEM;
queue = bcm43xx_setup_pioqueue(dev, BCM43xx_MMIO_PIO1_BASE);
if (!queue)
goto out;
pio->queue0 = queue;
queue = bcm43xx_setup_pioqueue(dev, BCM43xx_MMIO_PIO2_BASE);
if (!queue)
goto err_destroy0;
pio->queue1 = queue;
queue = bcm43xx_setup_pioqueue(dev, BCM43xx_MMIO_PIO3_BASE);
if (!queue)
goto err_destroy1;
pio->queue2 = queue;
queue = bcm43xx_setup_pioqueue(dev, BCM43xx_MMIO_PIO4_BASE);
if (!queue)
goto err_destroy2;
pio->queue3 = queue;
if (dev->dev->id.revision < 3)
dev->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND;
dprintk(KERN_INFO PFX "PIO initialized\n");
err = 0;
out:
return err;
err_destroy2:
bcm43xx_destroy_pioqueue(pio->queue2);
pio->queue2 = NULL;
err_destroy1:
bcm43xx_destroy_pioqueue(pio->queue1);
pio->queue1 = NULL;
err_destroy0:
bcm43xx_destroy_pioqueue(pio->queue0);
pio->queue0 = NULL;
goto out;
}
int bcm43xx_pio_tx(struct bcm43xx_wldev *dev,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl)
{
struct bcm43xx_pioqueue *queue = dev->pio.queue1;
struct bcm43xx_pio_txpacket *packet;
assert(!queue->tx_suspended);
assert(!list_empty(&queue->txfree));
packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
packet->skb = skb;
memset(&packet->txstat, 0, sizeof(packet->txstat));
memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
list_move_tail(&packet->list, &queue->txqueue);
queue->nr_txfree--;
queue->nr_tx_packets++;
assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS);
tasklet_schedule(&queue->txtask);
return 0;
}
void bcm43xx_pio_handle_txstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status)
{
struct bcm43xx_pioqueue *queue;
struct bcm43xx_pio_txpacket *packet;
queue = parse_cookie(dev, status->cookie, &packet);
assert(queue);
queue->tx_devq_packets--;
queue->tx_devq_used -= (packet->skb->len + sizeof(struct bcm43xx_txhdr_fw4));
if (status->acked)
packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
packet->txstat.retry_count = status->frame_count - 1;
ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
&(packet->txstat));
packet->skb = NULL;
free_txpacket(packet, 1);
/* If there are packets on the txqueue, poke the tasklet
* to transmit them.
*/
if (!list_empty(&queue->txqueue))
tasklet_schedule(&queue->txtask);
}
void bcm43xx_pio_get_tx_stats(struct bcm43xx_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
struct bcm43xx_pio *pio = &dev->pio;
struct bcm43xx_pioqueue *queue;
struct ieee80211_tx_queue_stats_data *data;
queue = pio->queue1;
data = &(stats->data[0]);
data->len = BCM43xx_PIO_MAXTXPACKETS - queue->nr_txfree;
data->limit = BCM43xx_PIO_MAXTXPACKETS;
data->count = queue->nr_tx_packets;
}
static void pio_rx_error(struct bcm43xx_pioqueue *queue,
int clear_buffers,
const char *error)
{
int i;
printkl("PIO RX error: %s\n", error);
bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
BCM43xx_PIO_RXCTL_READY);
if (clear_buffers) {
assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE);
for (i = 0; i < 15; i++) {
/* Dummy read. */
bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
}
}
}
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
{
u16 preamble[21] = { 0 };
struct bcm43xx_rxhdr_fw4 *rxhdr;
u16 tmp, len, macstat;
int i, preamble_readwords;
struct sk_buff *skb;
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE))
return;
bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
BCM43xx_PIO_RXCTL_DATAAVAILABLE);
for (i = 0; i < 10; i++) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
if (tmp & BCM43xx_PIO_RXCTL_READY)
goto data_ready;
udelay(10);
}
dprintkl(KERN_ERR PFX "PIO RX timed out\n");
return;
data_ready:
len = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
if (unlikely(len > 0x700)) {
pio_rx_error(queue, 0, "len > 0x700");
return;
}
if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) {
pio_rx_error(queue, 0, "len == 0");
return;
}
preamble[0] = cpu_to_le16(len);
if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE)
preamble_readwords = 14 / sizeof(u16);
else
preamble_readwords = 18 / sizeof(u16);
for (i = 0; i < preamble_readwords; i++) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
preamble[i + 1] = cpu_to_le16(tmp);
}
rxhdr = (struct bcm43xx_rxhdr_fw4 *)preamble;
macstat = le16_to_cpu(rxhdr->mac_status);
if (macstat & BCM43xx_RX_MAC_FCSERR) {
pio_rx_error(queue,
(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE),
"Frame FCS error");
return;
}
if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) {
/* We received an xmit status. */
struct bcm43xx_hwtxstatus *hw;
hw = (struct bcm43xx_hwtxstatus *)(preamble + 1);
bcm43xx_handle_hwtxstatus(queue->dev, hw);
return;
}
skb = dev_alloc_skb(len);
if (unlikely(!skb)) {
pio_rx_error(queue, 1, "OOM");
return;
}
skb_put(skb, len);
for (i = 0; i < len - 1; i += 2) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
*((u16 *)(skb->data + i)) = cpu_to_le16(tmp);
}
if (len % 2) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
skb->data[len - 1] = (tmp & 0x00FF);
/* The specs say the following is required, but
* it is wrong and corrupts the PLCP. If we don't do
* this, the PLCP seems to be correct. So ifdef it out for now.
*/
#if 0
if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
skb->data[2] = (tmp & 0xFF00) >> 8;
else
skb->data[0] = (tmp & 0xFF00) >> 8;
#endif
}
bcm43xx_rx(queue->dev, skb, rxhdr);
}
void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
{
bcm43xx_power_saving_ctl_bits(queue->dev, -1, 1);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
| BCM43xx_PIO_TXCTL_SUSPEND);
}
void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
{
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
& ~BCM43xx_PIO_TXCTL_SUSPEND);
bcm43xx_power_saving_ctl_bits(queue->dev, -1, -1);
tasklet_schedule(&queue->txtask);
}
void bcm43xx_pio_freeze_txqueues(struct bcm43xx_wldev *dev)
{
struct bcm43xx_pio *pio;
assert(bcm43xx_using_pio(dev));
pio = &dev->pio;
pio->queue0->tx_frozen = 1;
pio->queue1->tx_frozen = 1;
pio->queue2->tx_frozen = 1;
pio->queue3->tx_frozen = 1;
}
void bcm43xx_pio_thaw_txqueues(struct bcm43xx_wldev *dev)
{
struct bcm43xx_pio *pio;
assert(bcm43xx_using_pio(dev));
pio = &dev->pio;
pio->queue0->tx_frozen = 0;
pio->queue1->tx_frozen = 0;
pio->queue2->tx_frozen = 0;
pio->queue3->tx_frozen = 0;
if (!list_empty(&pio->queue0->txqueue))
tasklet_schedule(&pio->queue0->txtask);
if (!list_empty(&pio->queue1->txqueue))
tasklet_schedule(&pio->queue1->txtask);
if (!list_empty(&pio->queue2->txqueue))
tasklet_schedule(&pio->queue2->txtask);
if (!list_empty(&pio->queue3->txqueue))
tasklet_schedule(&pio->queue3->txtask);
}

View file

@ -0,0 +1,170 @@
#ifndef BCM43xx_PIO_H_
#define BCM43xx_PIO_H_
#include "bcm43xx.h"
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#define BCM43xx_PIO_TXCTL 0x00
#define BCM43xx_PIO_TXDATA 0x02
#define BCM43xx_PIO_TXQBUFSIZE 0x04
#define BCM43xx_PIO_RXCTL 0x08
#define BCM43xx_PIO_RXDATA 0x0A
#define BCM43xx_PIO_TXCTL_WRITELO (1 << 0)
#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 1)
#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2)
#define BCM43xx_PIO_TXCTL_INIT (1 << 3)
#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7)
#define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0)
#define BCM43xx_PIO_RXCTL_READY (1 << 1)
/* PIO constants */
#define BCM43xx_PIO_MAXTXDEVQPACKETS 31
#define BCM43xx_PIO_TXQADJUST 80
/* PIO tuning knobs */
#define BCM43xx_PIO_MAXTXPACKETS 256
#ifdef CONFIG_BCM43XX_MAC80211_PIO
struct bcm43xx_pioqueue;
struct bcm43xx_xmitstatus;
struct bcm43xx_pio_txpacket {
struct bcm43xx_pioqueue *queue;
struct sk_buff *skb;
struct ieee80211_tx_status txstat;
struct list_head list;
};
#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache))
struct bcm43xx_pioqueue {
struct bcm43xx_wldev *dev;
u16 mmio_base;
u8 tx_suspended:1,
tx_frozen:1,
need_workarounds:1; /* Workarounds needed for core.rev < 3 */
/* Adjusted size of the device internal TX buffer. */
u16 tx_devq_size;
/* Used octets of the device internal TX buffer. */
u16 tx_devq_used;
/* Used packet slots in the device internal TX buffer. */
u8 tx_devq_packets;
/* Packets from the txfree list can
* be taken on incoming TX requests.
*/
struct list_head txfree;
unsigned int nr_txfree;
/* Packets on the txqueue are queued,
* but not completely written to the chip, yet.
*/
struct list_head txqueue;
/* Packets on the txrunning queue are completely
* posted to the device. We are waiting for the txstatus.
*/
struct list_head txrunning;
/* Total number or packets sent.
* (This counter can obviously wrap).
*/
unsigned int nr_tx_packets;
struct tasklet_struct txtask;
struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS];
};
static inline
u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue,
u16 offset)
{
return bcm43xx_read16(queue->dev, queue->mmio_base + offset);
}
static inline
void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
u16 offset, u16 value)
{
bcm43xx_write16(queue->dev, queue->mmio_base + offset, value);
mmiowb();
}
int bcm43xx_pio_init(struct bcm43xx_wldev *dev);
void bcm43xx_pio_free(struct bcm43xx_wldev *dev);
int bcm43xx_pio_tx(struct bcm43xx_wldev *dev,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl);
void bcm43xx_pio_handle_txstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status);
void bcm43xx_pio_get_tx_stats(struct bcm43xx_wldev *dev,
struct ieee80211_tx_queue_stats *stats);
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
/* Suspend TX queue in hardware. */
void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
/* Suspend (freeze) the TX tasklet (software level). */
void bcm43xx_pio_freeze_txqueues(struct bcm43xx_wldev *dev);
void bcm43xx_pio_thaw_txqueues(struct bcm43xx_wldev *dev);
#else /* CONFIG_BCM43XX_MAC80211_PIO */
static inline
int bcm43xx_pio_init(struct bcm43xx_wldev *dev)
{
return 0;
}
static inline
void bcm43xx_pio_free(struct bcm43xx_wldev *dev)
{
}
static inline
int bcm43xx_pio_tx(struct bcm43xx_wldev *dev,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl)
{
return 0;
}
static inline
void bcm43xx_pio_handle_txstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status)
{
}
static inline
void bcm43xx_pio_get_tx_stats(struct bcm43xx_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
}
static inline
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
{
}
static inline
void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
{
}
static inline
void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
{
}
static inline
void bcm43xx_pio_freeze_txqueues(struct bcm43xx_wldev *dev)
{
}
static inline
void bcm43xx_pio_thaw_txqueues(struct bcm43xx_wldev *dev)
{
}
#endif /* CONFIG_BCM43XX_MAC80211_PIO */
#endif /* BCM43xx_PIO_H_ */

View file

@ -0,0 +1,82 @@
/*
Broadcom BCM43xx wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio <st3@riseup.net>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
Some parts of the code in this file are derived from the ipw2200
driver Copyright(c) 2003 - 2004 Intel Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <linux/delay.h>
#include "bcm43xx.h"
#include "bcm43xx_power.h"
#include "bcm43xx_main.h"
//TODO Kill this file.
/* Set the PowerSavingControlBits.
* Bitvalues:
* 0 => unset the bit
* 1 => set the bit
* -1 => calculate the bit
*/
void bcm43xx_power_saving_ctl_bits(struct bcm43xx_wldev *dev,
int bit25, int bit26)
{
int i;
u32 status;
//FIXME: Force 25 to off and 26 to on for now:
bit25 = 0;
bit26 = 1;
if (bit25 == -1) {
//TODO: If powersave is not off and FIXME is not set and we are not in adhoc
// and thus is not an AP and we are associated, set bit 25
}
if (bit26 == -1) {
//TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
// or we are associated, or FIXME, or the latest PS-Poll packet sent was
// successful, set bit26
}
status = bcm43xx_read32(dev, BCM43xx_MMIO_STATUS_BITFIELD);
if (bit25)
status |= BCM43xx_SBF_PS1;
else
status &= ~BCM43xx_SBF_PS1;
if (bit26)
status |= BCM43xx_SBF_PS2;
else
status &= ~BCM43xx_SBF_PS2;
bcm43xx_write32(dev, BCM43xx_MMIO_STATUS_BITFIELD, status);
if (bit26 && dev->dev->id.revision >= 5) {
for (i = 0; i < 100; i++) {
if (bcm43xx_shm_read32(dev, BCM43xx_SHM_SHARED, 0x0040) != 4)
break;
udelay(10);
}
}
}

View file

@ -0,0 +1,41 @@
/*
Broadcom BCM43xx wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio <st3@riseup.net>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
Some parts of the code in this file are derived from the ipw2200
driver Copyright(c) 2003 - 2004 Intel Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef BCM43xx_POWER_H_
#define BCM43xx_POWER_H_
//TODO kill this file
struct bcm43xx_wldev;
void bcm43xx_power_saving_ctl_bits(struct bcm43xx_wldev *dev,
int bit25, int bit26);
#endif /* BCM43xx_POWER_H_ */

View file

@ -0,0 +1,232 @@
/*
Broadcom BCM43xx wireless driver
SYSFS support routines
Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "bcm43xx_sysfs.h"
#include "bcm43xx.h"
#include "bcm43xx_main.h"
#include "bcm43xx_phy.h"
#include <linux/capability.h>
#define GENERIC_FILESIZE 64
static int get_integer(const char *buf, size_t count)
{
char tmp[10 + 1] = { 0 };
int ret = -EINVAL;
if (count == 0)
goto out;
count = min(count, (size_t)10);
memcpy(tmp, buf, count);
ret = simple_strtol(tmp, NULL, 10);
out:
return ret;
}
static int get_boolean(const char *buf, size_t count)
{
if (count != 0) {
if (buf[0] == '1')
return 1;
if (buf[0] == '0')
return 0;
if (count >= 4 && memcmp(buf, "true", 4) == 0)
return 1;
if (count >= 5 && memcmp(buf, "false", 5) == 0)
return 0;
if (count >= 3 && memcmp(buf, "yes", 3) == 0)
return 1;
if (count >= 2 && memcmp(buf, "no", 2) == 0)
return 0;
if (count >= 2 && memcmp(buf, "on", 2) == 0)
return 1;
if (count >= 3 && memcmp(buf, "off", 3) == 0)
return 0;
}
return -EINVAL;
}
static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct bcm43xx_wldev *wldev = dev_to_bcm43xx_wldev(dev);
ssize_t count = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mutex_lock(&wldev->wl->mutex);
switch (wldev->phy.interfmode) {
case BCM43xx_INTERFMODE_NONE:
count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n");
break;
case BCM43xx_INTERFMODE_NONWLAN:
count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n");
break;
case BCM43xx_INTERFMODE_MANUALWLAN:
count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n");
break;
default:
assert(0);
}
mutex_unlock(&wldev->wl->mutex);
return count;
}
static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bcm43xx_wldev *wldev = dev_to_bcm43xx_wldev(dev);
unsigned long flags;
int err;
int mode;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mode = get_integer(buf, count);
switch (mode) {
case 0:
mode = BCM43xx_INTERFMODE_NONE;
break;
case 1:
mode = BCM43xx_INTERFMODE_NONWLAN;
break;
case 2:
mode = BCM43xx_INTERFMODE_MANUALWLAN;
break;
case 3:
mode = BCM43xx_INTERFMODE_AUTOWLAN;
break;
default:
return -EINVAL;
}
mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
err = bcm43xx_radio_set_interference_mitigation(wldev, mode);
if (err) {
printk(KERN_ERR PFX "Interference Mitigation not "
"supported by device\n");
}
mmiowb();
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);
return err ? err : count;
}
static DEVICE_ATTR(interference, 0644,
bcm43xx_attr_interfmode_show,
bcm43xx_attr_interfmode_store);
static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct bcm43xx_wldev *wldev = dev_to_bcm43xx_wldev(dev);
ssize_t count;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mutex_lock(&wldev->wl->mutex);
if (wldev->short_preamble)
count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
else
count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
mutex_unlock(&wldev->wl->mutex);
return count;
}
static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bcm43xx_wldev *wldev = dev_to_bcm43xx_wldev(dev);
unsigned long flags;
int value;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
value = get_boolean(buf, count);
if (value < 0)
return value;
mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
wldev->short_preamble = !!value;
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);
return count;
}
static DEVICE_ATTR(shortpreamble, 0644,
bcm43xx_attr_preamble_show,
bcm43xx_attr_preamble_store);
int bcm43xx_sysfs_register(struct bcm43xx_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
int err;
assert(bcm43xx_status(wldev) == BCM43xx_STAT_INITIALIZED);
err = device_create_file(dev, &dev_attr_interference);
if (err)
goto out;
err = device_create_file(dev, &dev_attr_shortpreamble);
if (err)
goto err_remove_interfmode;
out:
return err;
err_remove_interfmode:
device_remove_file(dev, &dev_attr_interference);
goto out;
}
void bcm43xx_sysfs_unregister(struct bcm43xx_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);
}

View file

@ -0,0 +1,9 @@
#ifndef BCM43xx_SYSFS_H_
#define BCM43xx_SYSFS_H_
struct bcm43xx_wldev;
int bcm43xx_sysfs_register(struct bcm43xx_wldev *dev);
void bcm43xx_sysfs_unregister(struct bcm43xx_wldev *dev);
#endif /* BCM43xx_SYSFS_H_ */

View file

@ -0,0 +1,376 @@
/*
Broadcom BCM43xx wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "bcm43xx.h"
#include "bcm43xx_tables.h"
#include "bcm43xx_phy.h"
const u32 bcm43xx_tab_rotor[] = {
0xFEB93FFD, 0xFEC63FFD, /* 0 */
0xFED23FFD, 0xFEDF3FFD,
0xFEEC3FFE, 0xFEF83FFE,
0xFF053FFE, 0xFF113FFE,
0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
0xFF373FFF, 0xFF443FFF,
0xFF503FFF, 0xFF5D3FFF,
0xFF693FFF, 0xFF763FFF,
0xFF824000, 0xFF8F4000, /* 16 */
0xFF9B4000, 0xFFA84000,
0xFFB54000, 0xFFC14000,
0xFFCE4000, 0xFFDA4000,
0xFFE74000, 0xFFF34000, /* 24 */
0x00004000, 0x000D4000,
0x00194000, 0x00264000,
0x00324000, 0x003F4000,
0x004B4000, 0x00584000, /* 32 */
0x00654000, 0x00714000,
0x007E4000, 0x008A3FFF,
0x00973FFF, 0x00A33FFF,
0x00B03FFF, 0x00BC3FFF, /* 40 */
0x00C93FFF, 0x00D63FFF,
0x00E23FFE, 0x00EF3FFE,
0x00FB3FFE, 0x01083FFE,
0x01143FFE, 0x01213FFD, /* 48 */
0x012E3FFD, 0x013A3FFD,
0x01473FFD,
};
const u32 bcm43xx_tab_retard[] = {
0xDB93CB87, 0xD666CF64, /* 0 */
0xD1FDD358, 0xCDA6D826,
0xCA38DD9F, 0xC729E2B4,
0xC469E88E, 0xC26AEE2B,
0xC0DEF46C, 0xC073FA62, /* 8 */
0xC01D00D5, 0xC0760743,
0xC1560D1E, 0xC2E51369,
0xC4ED18FF, 0xC7AC1ED7,
0xCB2823B2, 0xCEFA28D9, /* 16 */
0xD2F62D3F, 0xD7BB3197,
0xDCE53568, 0xE1FE3875,
0xE7D13B35, 0xED663D35,
0xF39B3EC4, 0xF98E3FA7, /* 24 */
0x00004000, 0x06723FA7,
0x0C653EC4, 0x129A3D35,
0x182F3B35, 0x1E023875,
0x231B3568, 0x28453197, /* 32 */
0x2D0A2D3F, 0x310628D9,
0x34D823B2, 0x38541ED7,
0x3B1318FF, 0x3D1B1369,
0x3EAA0D1E, 0x3F8A0743, /* 40 */
0x3FE300D5, 0x3F8DFA62,
0x3F22F46C, 0x3D96EE2B,
0x3B97E88E, 0x38D7E2B4,
0x35C8DD9F, 0x325AD826, /* 48 */
0x2E03D358, 0x299ACF64,
0x246DCB87,
};
const u16 bcm43xx_tab_finefreqa[] = {
0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
0x0202, 0x0282, 0x0302, 0x0382,
0x0402, 0x0482, 0x0502, 0x0582,
0x05E2, 0x0662, 0x06E2, 0x0762,
0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
0x09C2, 0x0A22, 0x0AA2, 0x0B02,
0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
0x0D42, 0x0DA2, 0x0E02, 0x0E62,
0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
0x1062, 0x10C2, 0x1122, 0x1182,
0x11E2, 0x1242, 0x12A2, 0x12E2,
0x1342, 0x13A2, 0x1402, 0x1442,
0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
0x15E2, 0x1622, 0x1662, 0x16C1,
0x1701, 0x1741, 0x1781, 0x17E1,
0x1821, 0x1861, 0x18A1, 0x18E1,
0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
0x1B01, 0x1B41, 0x1B81, 0x1BA1,
0x1BE1, 0x1C21, 0x1C41, 0x1C81,
0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
0x1E21, 0x1E61, 0x1E81, 0x1EA1,
0x1EE1, 0x1F01, 0x1F21, 0x1F41,
0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
0x2001, 0x2041, 0x2061, 0x2081,
0x20A1, 0x20C1, 0x20E1, 0x2101,
0x2121, 0x2141, 0x2161, 0x2181,
0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
0x2221, 0x2241, 0x2261, 0x2281,
0x22A1, 0x22C1, 0x22C1, 0x22E1,
0x2301, 0x2321, 0x2341, 0x2361,
0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
0x23E1, 0x23E1, 0x2401, 0x2421,
0x2441, 0x2441, 0x2461, 0x2481,
0x2481, 0x24A1, 0x24C1, 0x24C1,
0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
0x2541, 0x2541, 0x2561, 0x2561,
0x2581, 0x25A1, 0x25A1, 0x25C1,
0x25C1, 0x25E1, 0x2601, 0x2601,
0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
0x2661, 0x2661, 0x2681, 0x2681,
0x26A1, 0x26A1, 0x26C1, 0x26C1,
0x26E1, 0x26E1, 0x2701, 0x2701,
0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
0x2760, 0x2760, 0x2780, 0x2780,
0x2780, 0x27A0, 0x27A0, 0x27C0,
0x27C0, 0x27E0, 0x27E0, 0x27E0,
0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
0x2820, 0x2840, 0x2840, 0x2840,
0x2860, 0x2860, 0x2880, 0x2880,
0x2880, 0x28A0, 0x28A0, 0x28A0,
0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
0x28E0, 0x28E0, 0x2900, 0x2900,
0x2900, 0x2920, 0x2920, 0x2920,
0x2940, 0x2940, 0x2940, 0x2960,
0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
0x2980, 0x2980, 0x29A0, 0x29A0,
0x29A0, 0x29A0, 0x29C0, 0x29C0,
0x29C0, 0x29E0, 0x29E0, 0x29E0,
0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
0x2A00, 0x2A20, 0x2A20, 0x2A20,
0x2A20, 0x2A40, 0x2A40, 0x2A40,
0x2A40, 0x2A60, 0x2A60, 0x2A60,
};
const u16 bcm43xx_tab_finefreqg[] = {
0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
0x05A9, 0x0669, 0x0709, 0x0789,
0x0829, 0x08A9, 0x0929, 0x0989,
0x0A09, 0x0A69, 0x0AC9, 0x0B29,
0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
0x0D09, 0x0D69, 0x0DA9, 0x0E09,
0x0E69, 0x0EA9, 0x0F09, 0x0F49,
0x0FA9, 0x0FE9, 0x1029, 0x1089,
0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
0x11E9, 0x1229, 0x1289, 0x12C9,
0x1309, 0x1349, 0x1389, 0x13C9,
0x1409, 0x1449, 0x14A9, 0x14E9,
0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
0x1629, 0x1669, 0x16A9, 0x16E8,
0x1728, 0x1768, 0x17A8, 0x17E8,
0x1828, 0x1868, 0x18A8, 0x18E8,
0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
0x1E48, 0x1E88, 0x1EC8, 0x1F08,
0x1F48, 0x1F88, 0x1FE8, 0x2028,
0x2068, 0x20A8, 0x2108, 0x2148,
0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
0x22C8, 0x2308, 0x2348, 0x23A8,
0x23E8, 0x2448, 0x24A8, 0x24E8,
0x2548, 0x25A8, 0x2608, 0x2668,
0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
0x2847, 0x28C7, 0x2947, 0x29A7,
0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
0x2CA7, 0x2D67, 0x2E47, 0x2F67,
0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
0x3806, 0x38A6, 0x3946, 0x39E6,
0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
0x3C45, 0x3CA5, 0x3D05, 0x3D85,
0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
0x3F45, 0x3FA5, 0x4005, 0x4045,
0x40A5, 0x40E5, 0x4145, 0x4185,
0x41E5, 0x4225, 0x4265, 0x42C5,
0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
0x4424, 0x4464, 0x44C4, 0x4504,
0x4544, 0x4584, 0x45C4, 0x4604,
0x4644, 0x46A4, 0x46E4, 0x4724,
0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
0x4864, 0x48A4, 0x48E4, 0x4924,
0x4964, 0x49A4, 0x49E4, 0x4A24,
0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
0x5083, 0x50C3, 0x5103, 0x5143,
0x5183, 0x51E2, 0x5222, 0x5262,
0x52A2, 0x52E2, 0x5342, 0x5382,
0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
0x5502, 0x5542, 0x55A2, 0x55E2,
0x5642, 0x5682, 0x56E2, 0x5722,
0x5782, 0x57E1, 0x5841, 0x58A1,
0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
0x5C61, 0x5D01, 0x5D80, 0x5E20,
0x5EE0, 0x5FA0, 0x6080, 0x61C0,
};
const u16 bcm43xx_tab_noisea2[] = {
0x0001, 0x0001, 0x0001, 0xFFFE,
0xFFFE, 0x3FFF, 0x1000, 0x0393,
};
const u16 bcm43xx_tab_noisea3[] = {
0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
};
const u16 bcm43xx_tab_noiseg1[] = {
0x013C, 0x01F5, 0x031A, 0x0631,
0x0001, 0x0001, 0x0001, 0x0001,
};
const u16 bcm43xx_tab_noiseg2[] = {
0x5484, 0x3C40, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
};
const u16 bcm43xx_tab_noisescaleg1[] = {
0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
0x2F2D, 0x2A2A, 0x2527, 0x1F21,
0x1A1D, 0x1719, 0x1616, 0x1414,
0x1414, 0x1400, 0x1414, 0x1614,
0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
0x2A27, 0x2F2A, 0x332D, 0x3B35,
0x5140, 0x6C62, 0x0077,
};
const u16 bcm43xx_tab_noisescaleg2[] = {
0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
0x969B, 0x9195, 0x8F8F, 0x8A8A,
0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
0xCBC0, 0xD8D4, 0x00DD,
};
const u16 bcm43xx_tab_noisescaleg3[] = {
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
0xA4A4, 0xA4A4, 0x00A4,
};
const u16 bcm43xx_tab_sigmasqr1[] = {
0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
0x0067, 0x0063, 0x005E, 0x0059,
0x0054, 0x0050, 0x004B, 0x0046,
0x0042, 0x003D, 0x003D, 0x003D,
0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
0x003D, 0x003D, 0x003D, 0x003D,
0x003D, 0x003D, 0x0000, 0x003D,
0x003D, 0x003D, 0x003D, 0x003D,
0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
0x003D, 0x003D, 0x003D, 0x003D,
0x0042, 0x0046, 0x004B, 0x0050,
0x0054, 0x0059, 0x005E, 0x0063,
0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
0x007A,
};
const u16 bcm43xx_tab_sigmasqr2[] = {
0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
0x00D6, 0x00D4, 0x00D2, 0x00CF,
0x00CD, 0x00CA, 0x00C7, 0x00C4,
0x00C1, 0x00BE, 0x00BE, 0x00BE,
0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
0x00BE, 0x00BE, 0x00BE, 0x00BE,
0x00BE, 0x00BE, 0x0000, 0x00BE,
0x00BE, 0x00BE, 0x00BE, 0x00BE,
0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
0x00BE, 0x00BE, 0x00BE, 0x00BE,
0x00C1, 0x00C4, 0x00C7, 0x00CA,
0x00CD, 0x00CF, 0x00D2, 0x00D4,
0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
0x00DE,
};
static inline void assert_sizes(void)
{
BUILD_BUG_ON(BCM43xx_TAB_ROTOR_SIZE != ARRAY_SIZE(bcm43xx_tab_rotor));
BUILD_BUG_ON(BCM43xx_TAB_RETARD_SIZE != ARRAY_SIZE(bcm43xx_tab_retard));
BUILD_BUG_ON(BCM43xx_TAB_FINEFREQA_SIZE != ARRAY_SIZE(bcm43xx_tab_finefreqa));
BUILD_BUG_ON(BCM43xx_TAB_FINEFREQG_SIZE != ARRAY_SIZE(bcm43xx_tab_finefreqg));
BUILD_BUG_ON(BCM43xx_TAB_NOISEA2_SIZE != ARRAY_SIZE(bcm43xx_tab_noisea2));
BUILD_BUG_ON(BCM43xx_TAB_NOISEA3_SIZE != ARRAY_SIZE(bcm43xx_tab_noisea3));
BUILD_BUG_ON(BCM43xx_TAB_NOISEG1_SIZE != ARRAY_SIZE(bcm43xx_tab_noiseg1));
BUILD_BUG_ON(BCM43xx_TAB_NOISEG2_SIZE != ARRAY_SIZE(bcm43xx_tab_noiseg2));
BUILD_BUG_ON(BCM43xx_TAB_NOISESCALEG_SIZE != ARRAY_SIZE(bcm43xx_tab_noisescaleg1));
BUILD_BUG_ON(BCM43xx_TAB_NOISESCALEG_SIZE != ARRAY_SIZE(bcm43xx_tab_noisescaleg2));
BUILD_BUG_ON(BCM43xx_TAB_NOISESCALEG_SIZE != ARRAY_SIZE(bcm43xx_tab_noisescaleg3));
BUILD_BUG_ON(BCM43xx_TAB_SIGMASQR_SIZE != ARRAY_SIZE(bcm43xx_tab_sigmasqr1));
BUILD_BUG_ON(BCM43xx_TAB_SIGMASQR_SIZE != ARRAY_SIZE(bcm43xx_tab_sigmasqr2));
}
u16 bcm43xx_ofdmtab_read16(struct bcm43xx_wldev *dev, u16 table, u16 offset)
{
assert_sizes();
bcm43xx_phy_write(dev, BCM43xx_PHY_OTABLECTL, table + offset);
return bcm43xx_phy_read(dev, BCM43xx_PHY_OTABLEI);
}
void bcm43xx_ofdmtab_write16(struct bcm43xx_wldev *dev, u16 table,
u16 offset, u16 value)
{
bcm43xx_phy_write(dev, BCM43xx_PHY_OTABLECTL, table + offset);
bcm43xx_phy_write(dev, BCM43xx_PHY_OTABLEI, value);
}
u32 bcm43xx_ofdmtab_read32(struct bcm43xx_wldev *dev, u16 table, u16 offset)
{
u32 ret;
bcm43xx_phy_write(dev, BCM43xx_PHY_OTABLECTL, table + offset);
ret = bcm43xx_phy_read(dev, BCM43xx_PHY_OTABLEQ);
ret <<= 16;
ret |= bcm43xx_phy_read(dev, BCM43xx_PHY_OTABLEI);
return ret;
}
void bcm43xx_ofdmtab_write32(struct bcm43xx_wldev *dev, u16 table,
u16 offset, u32 value)
{
bcm43xx_phy_write(dev, BCM43xx_PHY_OTABLECTL, table + offset);
bcm43xx_phy_write(dev, BCM43xx_PHY_OTABLEI, value);
bcm43xx_phy_write(dev, BCM43xx_PHY_OTABLEQ, (value >> 16));
}
u16 bcm43xx_gtab_read(struct bcm43xx_wldev *dev, u16 table, u16 offset)
{
bcm43xx_phy_write(dev, BCM43xx_PHY_GTABCTL, table + offset);
return bcm43xx_phy_read(dev, BCM43xx_PHY_GTABDATA);
}
void bcm43xx_gtab_write(struct bcm43xx_wldev *dev, u16 table,
u16 offset, u16 value)
{
bcm43xx_phy_write(dev, BCM43xx_PHY_GTABCTL, table + offset);
bcm43xx_phy_write(dev, BCM43xx_PHY_GTABDATA, value);
}

View file

@ -0,0 +1,28 @@
#ifndef BCM43xx_TABLES_H_
#define BCM43xx_TABLES_H_
#define BCM43xx_TAB_ROTOR_SIZE 53
extern const u32 bcm43xx_tab_rotor[];
#define BCM43xx_TAB_RETARD_SIZE 53
extern const u32 bcm43xx_tab_retard[];
#define BCM43xx_TAB_FINEFREQA_SIZE 256
extern const u16 bcm43xx_tab_finefreqa[];
#define BCM43xx_TAB_FINEFREQG_SIZE 256
extern const u16 bcm43xx_tab_finefreqg[];
#define BCM43xx_TAB_NOISEA2_SIZE 8
extern const u16 bcm43xx_tab_noisea2[];
#define BCM43xx_TAB_NOISEA3_SIZE 8
extern const u16 bcm43xx_tab_noisea3[];
#define BCM43xx_TAB_NOISEG1_SIZE 8
extern const u16 bcm43xx_tab_noiseg1[];
#define BCM43xx_TAB_NOISEG2_SIZE 8
extern const u16 bcm43xx_tab_noiseg2[];
#define BCM43xx_TAB_NOISESCALEG_SIZE 27
extern const u16 bcm43xx_tab_noisescaleg1[];
extern const u16 bcm43xx_tab_noisescaleg2[];
extern const u16 bcm43xx_tab_noisescaleg3[];
#define BCM43xx_TAB_SIGMASQR_SIZE 53
extern const u16 bcm43xx_tab_sigmasqr1[];
extern const u16 bcm43xx_tab_sigmasqr2[];
#endif /* BCM43xx_TABLES_H_ */

View file

@ -0,0 +1,603 @@
/*
Broadcom BCM43xx wireless driver
Transmission (TX/RX) related functions.
Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "bcm43xx_xmit.h"
#include "bcm43xx_phy.h"
#include "bcm43xx_dma.h"
#include "bcm43xx_pio.h"
/* Extract the bitrate out of a CCK PLCP header. */
static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr6 *plcp)
{
switch (plcp->raw[0]) {
case 0x0A:
return BCM43xx_CCK_RATE_1MB;
case 0x14:
return BCM43xx_CCK_RATE_2MB;
case 0x37:
return BCM43xx_CCK_RATE_5MB;
case 0x6E:
return BCM43xx_CCK_RATE_11MB;
}
assert(0);
return 0;
}
/* Extract the bitrate out of an OFDM PLCP header. */
static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr6 *plcp)
{
switch (plcp->raw[0] & 0xF) {
case 0xB:
return BCM43xx_OFDM_RATE_6MB;
case 0xF:
return BCM43xx_OFDM_RATE_9MB;
case 0xA:
return BCM43xx_OFDM_RATE_12MB;
case 0xE:
return BCM43xx_OFDM_RATE_18MB;
case 0x9:
return BCM43xx_OFDM_RATE_24MB;
case 0xD:
return BCM43xx_OFDM_RATE_36MB;
case 0x8:
return BCM43xx_OFDM_RATE_48MB;
case 0xC:
return BCM43xx_OFDM_RATE_54MB;
}
assert(0);
return 0;
}
u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
{
switch (bitrate) {
case BCM43xx_CCK_RATE_1MB:
return 0x0A;
case BCM43xx_CCK_RATE_2MB:
return 0x14;
case BCM43xx_CCK_RATE_5MB:
return 0x37;
case BCM43xx_CCK_RATE_11MB:
return 0x6E;
}
assert(0);
return 0;
}
u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
{
switch (bitrate) {
case BCM43xx_OFDM_RATE_6MB:
return 0xB;
case BCM43xx_OFDM_RATE_9MB:
return 0xF;
case BCM43xx_OFDM_RATE_12MB:
return 0xA;
case BCM43xx_OFDM_RATE_18MB:
return 0xE;
case BCM43xx_OFDM_RATE_24MB:
return 0x9;
case BCM43xx_OFDM_RATE_36MB:
return 0xD;
case BCM43xx_OFDM_RATE_48MB:
return 0x8;
case BCM43xx_OFDM_RATE_54MB:
return 0xC;
}
assert(0);
return 0;
}
void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
const u16 octets, const u8 bitrate)
{
__le32 *data = &(plcp->data);
__u8 *raw = plcp->raw;
if (bcm43xx_is_ofdm_rate(bitrate)) {
*data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
assert(!(octets & 0xF000));
*data |= (octets << 5);
*data = cpu_to_le32(*data);
} else {
u32 plen;
plen = octets * 16 / bitrate;
if ((octets * 16 % bitrate) > 0) {
plen++;
if ((bitrate == BCM43xx_CCK_RATE_11MB)
&& ((octets * 8 % 11) < 4)) {
raw[1] = 0x84;
} else
raw[1] = 0x04;
} else
raw[1] = 0x04;
*data |= cpu_to_le32(plen << 16);
raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
}
}
static u8 bcm43xx_calc_fallback_rate(u8 bitrate)
{
switch (bitrate) {
case BCM43xx_CCK_RATE_1MB:
return BCM43xx_CCK_RATE_1MB;
case BCM43xx_CCK_RATE_2MB:
return BCM43xx_CCK_RATE_1MB;
case BCM43xx_CCK_RATE_5MB:
return BCM43xx_CCK_RATE_2MB;
case BCM43xx_CCK_RATE_11MB:
return BCM43xx_CCK_RATE_5MB;
case BCM43xx_OFDM_RATE_6MB:
return BCM43xx_CCK_RATE_5MB;
case BCM43xx_OFDM_RATE_9MB:
return BCM43xx_OFDM_RATE_6MB;
case BCM43xx_OFDM_RATE_12MB:
return BCM43xx_OFDM_RATE_9MB;
case BCM43xx_OFDM_RATE_18MB:
return BCM43xx_OFDM_RATE_12MB;
case BCM43xx_OFDM_RATE_24MB:
return BCM43xx_OFDM_RATE_18MB;
case BCM43xx_OFDM_RATE_36MB:
return BCM43xx_OFDM_RATE_24MB;
case BCM43xx_OFDM_RATE_48MB:
return BCM43xx_OFDM_RATE_36MB;
case BCM43xx_OFDM_RATE_54MB:
return BCM43xx_OFDM_RATE_48MB;
}
assert(0);
return 0;
}
static void generate_txhdr_fw4(struct bcm43xx_wldev *dev,
struct bcm43xx_txhdr_fw4 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl,
u16 cookie)
{
const struct bcm43xx_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data;
int use_encryption = ((!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) &&
(txctl->key_idx >= 0));
u16 fctl = le16_to_cpu(wlhdr->frame_control);
u8 rate, rate_fb;
int rate_ofdm, rate_fb_ofdm;
unsigned int plcp_fragment_len;
u32 mac_ctl = 0;
u16 phy_ctl = 0;
u8 extra_ft = 0;
memset(txhdr, 0, sizeof(*txhdr));
rate = txctl->tx_rate;
rate_ofdm = bcm43xx_is_ofdm_rate(rate);
rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
rate_fb_ofdm = bcm43xx_is_ofdm_rate(rate_fb);
if (rate_ofdm)
txhdr->phy_rate = bcm43xx_plcp_get_ratecode_ofdm(rate);
else
txhdr->phy_rate = bcm43xx_plcp_get_ratecode_cck(rate);
txhdr->mac_frame_ctl = wlhdr->frame_control;
memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
/* Calculate duration for fallback rate */
if ((rate_fb == rate) ||
(wlhdr->duration_id & cpu_to_le16(0x8000)) ||
(wlhdr->duration_id == cpu_to_le16(0))) {
/* If the fallback rate equals the normal rate or the
* dur_id field contains an AID, CFP magic or 0,
* use the original dur_id field. */
txhdr->dur_fb = wlhdr->duration_id;
} else {
int fbrate_base100kbps = BCM43xx_RATE_TO_BASE100KBPS(rate_fb);
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
fragment_len,
fbrate_base100kbps);
}
plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) {
u8 key_idx = (u16)(txctl->key_idx);
struct bcm43xx_key *key;
int wlhdr_len;
size_t iv_len;
assert(key_idx < dev->max_nr_keys);
key = &(dev->key[key_idx]);
if (key->enabled) {
/* Hardware appends ICV. */
plcp_fragment_len += txctl->icv_len;
key_idx = bcm43xx_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << BCM43xx_TX4_MAC_KEYIDX_SHIFT) &
BCM43xx_TX4_MAC_KEYIDX;
mac_ctl |= (key->algorithm << BCM43xx_TX4_MAC_KEYALG_SHIFT) &
BCM43xx_TX4_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl);
iv_len = min((size_t)txctl->iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
}
}
bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
plcp_fragment_len, rate);
bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp_fb),
plcp_fragment_len, rate_fb);
/* Extra Frame Types */
if (rate_fb_ofdm)
extra_ft |= BCM43xx_TX4_EFT_FBOFDM;
/* Set channel radio code. Note that the micrcode ORs 0x100 to
* this value before comparing it to the value in SHM, if this
* is a 5Ghz packet.
*/
txhdr->chan_radio_code = phy->channel;
/* PHY TX Control word */
if (rate_ofdm)
phy_ctl |= BCM43xx_TX4_PHY_OFDM;
if (dev->short_preamble)
phy_ctl |= BCM43xx_TX4_PHY_SHORTPRMBL;
switch (txctl->antenna_sel_tx) {
case 0:
phy_ctl |= BCM43xx_TX4_PHY_ANTLAST;
break;
case 1:
phy_ctl |= BCM43xx_TX4_PHY_ANT0;
break;
case 2:
phy_ctl |= BCM43xx_TX4_PHY_ANT1;
break;
default:
assert(0);
}
/* MAC control */
if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
mac_ctl |= BCM43xx_TX4_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= BCM43xx_TX4_MAC_HWSEQ;
if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
mac_ctl |= BCM43xx_TX4_MAC_STMSDU;
if (phy->type == BCM43xx_PHYTYPE_A)
mac_ctl |= BCM43xx_TX4_MAC_5GHZ;
/* Generate the RTS or CTS-to-self frame */
if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
(txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb;
int rts_rate_ofdm, rts_rate_fb_ofdm;
rts_rate = txctl->rts_cts_rate;
rts_rate_ofdm = bcm43xx_is_ofdm_rate(rts_rate);
rts_rate_fb = bcm43xx_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = bcm43xx_is_ofdm_rate(rts_rate_fb);
if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
ieee80211_ctstoself_get(dev->wl->hw,
fragment_data, fragment_len, txctl,
(struct ieee80211_cts *)(txhdr->rts_frame));
mac_ctl |= BCM43xx_TX4_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts);
} else {
ieee80211_rts_get(dev->wl->hw,
fragment_data, fragment_len, txctl,
(struct ieee80211_rts *)(txhdr->rts_frame));
mac_ctl |= BCM43xx_TX4_MAC_SENDRTS;
len = sizeof(struct ieee80211_rts);
}
len += FCS_LEN;
bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_plcp),
len, rts_rate);
bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_plcp_fb),
len, rts_rate_fb);
hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
txhdr->rts_dur_fb = hdr->duration_id;
if (rts_rate_ofdm) {
extra_ft |= BCM43xx_TX4_EFT_RTSOFDM;
txhdr->phy_rate_rts = bcm43xx_plcp_get_ratecode_ofdm(rts_rate);
} else
txhdr->phy_rate_rts = bcm43xx_plcp_get_ratecode_cck(rts_rate);
if (rts_rate_fb_ofdm)
extra_ft |= BCM43xx_TX4_EFT_RTSFBOFDM;
mac_ctl |= BCM43xx_TX4_MAC_LONGFRAME;
}
/* Magic cookie */
txhdr->cookie = cpu_to_le16(cookie);
/* Apply the bitfields */
txhdr->mac_ctl = cpu_to_le32(mac_ctl);
txhdr->phy_ctl = cpu_to_le16(phy_ctl);
txhdr->extra_ft = extra_ft;
}
void bcm43xx_generate_txhdr(struct bcm43xx_wldev *dev,
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl,
u16 cookie)
{
generate_txhdr_fw4(dev, (struct bcm43xx_txhdr_fw4 *)txhdr,
fragment_data, fragment_len,
txctl, cookie);
}
static s8 bcm43xx_rssi_postprocess(struct bcm43xx_wldev *dev,
u8 in_rssi, int ofdm,
int adjust_2053, int adjust_2050)
{
struct bcm43xx_phy *phy = &dev->phy;
s32 tmp;
switch (phy->radio_ver) {
case 0x2050:
if (ofdm) {
tmp = in_rssi;
if (tmp > 127)
tmp -= 256;
tmp *= 73;
tmp /= 64;
if (adjust_2050)
tmp += 25;
else
tmp -= 3;
} else {
if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) {
if (in_rssi > 63)
in_rssi = 63;
tmp = phy->nrssi_lt[in_rssi];
tmp = 31 - tmp;
tmp *= -131;
tmp /= 128;
tmp -= 57;
} else {
tmp = in_rssi;
tmp = 31 - tmp;
tmp *= -149;
tmp /= 128;
tmp -= 68;
}
if (phy->type == BCM43xx_PHYTYPE_G &&
adjust_2050)
tmp += 25;
}
break;
case 0x2060:
if (in_rssi > 127)
tmp = in_rssi - 256;
else
tmp = in_rssi;
break;
default:
tmp = in_rssi;
tmp -= 11;
tmp *= 103;
tmp /= 64;
if (adjust_2053)
tmp -= 109;
else
tmp -= 83;
}
return (s8)tmp;
}
//TODO
#if 0
static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_wldev *dev,
u8 in_rssi)
{
struct bcm43xx_phy *phy = &dev->phy;
s8 ret;
if (phy->type == BCM43xx_PHYTYPE_A) {
//TODO: Incomplete specs.
ret = 0;
} else
ret = bcm43xx_rssi_postprocess(dev, in_rssi, 0, 1, 1);
return ret;
}
#endif
void bcm43xx_rx(struct bcm43xx_wldev *dev,
struct sk_buff *skb,
const void *_rxhdr)
{
struct ieee80211_rx_status status;
struct bcm43xx_plcp_hdr6 *plcp;
struct ieee80211_hdr *wlhdr;
const struct bcm43xx_rxhdr_fw4 *rxhdr = _rxhdr;
u16 fctl;
u16 phystat0, phystat3, chanstat, mactime;
u32 macstat;
u16 chanid;
u8 jssi;
int padding;
memset(&status, 0, sizeof(status));
/* Get metadata about the frame from the header. */
phystat0 = le16_to_cpu(rxhdr->phy_status0);
phystat3 = le16_to_cpu(rxhdr->phy_status3);
jssi = rxhdr->jssi;
macstat = le32_to_cpu(rxhdr->mac_status);
mactime = le16_to_cpu(rxhdr->mac_time);
chanstat = le16_to_cpu(rxhdr->channel);
if (macstat & BCM43xx_RX_MAC_FCSERR)
dev->wl->ieee_stats.dot11FCSErrorCount++;
/* Skip PLCP and padding */
padding = (macstat & BCM43xx_RX_MAC_PADDING) ? 2 : 0;
plcp = (struct bcm43xx_plcp_hdr6 *)(skb->data + padding);
skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6) + padding);
/* The skb contains the Wireless Header + payload data now */
wlhdr = (struct ieee80211_hdr *)(skb->data);
fctl = le16_to_cpu(wlhdr->frame_control);
skb_trim(skb, skb->len - FCS_LEN);
if ((macstat & BCM43xx_RX_MAC_DEC) &&
!(macstat & BCM43xx_RX_MAC_DECERR)) {
unsigned int keyidx;
int wlhdr_len;
int iv_len;
int icv_len;
keyidx = ((macstat & BCM43xx_RX_MAC_KEYIDX)
>> BCM43xx_RX_MAC_KEYIDX_SHIFT);
/* We must adjust the key index here. We want the "physical"
* key index, but the ucode passed it slightly different.
*/
keyidx = bcm43xx_kidx_to_raw(dev, keyidx);
assert(keyidx < dev->max_nr_keys);
if (dev->key[keyidx].algorithm != BCM43xx_SEC_ALGO_NONE) {
/* Remove PROTECTED flag to mark it as decrypted. */
assert(fctl & IEEE80211_FCTL_PROTECTED);
fctl &= ~IEEE80211_FCTL_PROTECTED;
wlhdr->frame_control = cpu_to_le16(fctl);
wlhdr_len = ieee80211_get_hdrlen(fctl);
if (skb->data[wlhdr_len + 3] & (1 << 5)) {
/* The Ext-IV Bit is set in the "KeyID"
* octet of the IV.
*/
iv_len = 8;
icv_len = 8;
} else {
iv_len = 4;
icv_len = 4;
}
/* Remove the IV */
memmove(skb->data + iv_len, skb->data, wlhdr_len);
skb_pull(skb, iv_len);
/* Remove the ICV */
skb_trim(skb, skb->len - icv_len);
status.flag |= RX_FLAG_DECRYPTED;
}
}
status.ssi = bcm43xx_rssi_postprocess(dev, jssi,
(phystat0 & BCM43xx_RX_PHYST0_OFDM),
(phystat0 & BCM43xx_RX_PHYST0_GAINCTL),
(phystat3 & BCM43xx_RX_PHYST3_TRSTATE));
status.noise = dev->stats.link_noise;
status.signal = jssi; /* this looks wrong, but is what mac80211 wants */
if (phystat0 & BCM43xx_RX_PHYST0_OFDM)
status.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
else
status.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
status.antenna = !!(phystat0 & BCM43xx_RX_PHYST0_ANT);
status.mactime = mactime;
chanid = (chanstat & BCM43xx_RX_CHAN_ID) >> BCM43xx_RX_CHAN_ID_SHIFT;
switch (chanstat & BCM43xx_RX_CHAN_PHYTYPE) {
case BCM43xx_PHYTYPE_A:
status.phymode = MODE_IEEE80211A;
status.freq = chanid;
status.channel = bcm43xx_freq_to_channel_a(chanid);
break;
case BCM43xx_PHYTYPE_B:
status.phymode = MODE_IEEE80211B;
status.freq = chanid + 2400;
status.channel = bcm43xx_freq_to_channel_bg(chanid + 2400);
break;
case BCM43xx_PHYTYPE_G:
status.phymode = MODE_IEEE80211G;
status.freq = chanid + 2400;
status.channel = bcm43xx_freq_to_channel_bg(chanid + 2400);
break;
default:
assert(0);
}
dev->stats.last_rx = jiffies;
ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
}
void bcm43xx_handle_txstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status)
{
bcm43xx_debugfs_log_txstat(dev, status);
if (status->intermediate)
return;
if (status->for_ampdu)
return;
if (!status->acked)
dev->wl->ieee_stats.dot11ACKFailureCount++;
if (status->rts_count) {
if (status->rts_count == 0xF) //FIXME
dev->wl->ieee_stats.dot11RTSFailureCount++;
else
dev->wl->ieee_stats.dot11RTSSuccessCount++;
}
if (bcm43xx_using_pio(dev))
bcm43xx_pio_handle_txstatus(dev, status);
else
bcm43xx_dma_handle_txstatus(dev, status);
}
/* Handle TX status report as received through DMA/PIO queues */
void bcm43xx_handle_hwtxstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_hwtxstatus *hw)
{
struct bcm43xx_txstatus status;
u8 tmp;
status.cookie = le16_to_cpu(hw->cookie);
status.seq = le16_to_cpu(hw->seq);
status.phy_stat = hw->phy_stat;
tmp = hw->count;
status.frame_count = (tmp >> 4);
status.rts_count = (tmp & 0x0F);
tmp = hw->flags;
status.supp_reason = ((tmp & 0x1C) >> 2);
status.pm_indicated = !!(tmp & 0x80);
status.intermediate = !!(tmp & 0x40);
status.for_ampdu = !!(tmp & 0x20);
status.acked = !!(tmp & 0x02);
bcm43xx_handle_txstatus(dev, &status);
}

View file

@ -0,0 +1,250 @@
#ifndef BCM43xx_XMIT_H_
#define BCM43xx_XMIT_H_
#include "bcm43xx_main.h"
#define _bcm43xx_declare_plcp_hdr(size) \
struct bcm43xx_plcp_hdr##size { \
union { \
__le32 data; \
__u8 raw[size]; \
} __attribute__((__packed__)); \
} __attribute__((__packed__))
/* struct bcm43xx_plcp_hdr4 */
_bcm43xx_declare_plcp_hdr(4);
/* struct bcm43xx_plcp_hdr6 */
_bcm43xx_declare_plcp_hdr(6);
#undef _bcm43xx_declare_plcp_hdr
/* TX header for v4 firmware */
struct bcm43xx_txhdr_fw4 {
__le32 mac_ctl; /* MAC TX control */
__le16 mac_frame_ctl; /* Copy of the FrameControl field */
__le16 tx_fes_time_norm; /* TX FES Time Normal */
__le16 phy_ctl; /* PHY TX control */
__le16 phy_ctl_0; /* Unused */
__le16 phy_ctl_1; /* Unused */
__le16 phy_ctl_rts_0; /* Unused */
__le16 phy_ctl_rts_1; /* Unused */
__u8 phy_rate; /* PHY rate */
__u8 phy_rate_rts; /* PHY rate for RTS/CTS */
__u8 extra_ft; /* Extra Frame Types */
__u8 chan_radio_code; /* Channel Radio Code */
__u8 iv[16]; /* Encryption IV */
__u8 tx_receiver[6]; /* TX Frame Receiver address */
__le16 tx_fes_time_fb; /* TX FES Time Fallback */
struct bcm43xx_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */
__le16 rts_dur_fb; /* RTS fallback duration */
struct bcm43xx_plcp_hdr6 plcp_fb; /* Fallback PLCP */
__le16 dur_fb; /* Fallback duration */
__le16 mm_dur_time; /* Unused */
__le16 mm_dur_time_fb; /* Unused */
__le32 time_stamp; /* Timestamp */
PAD_BYTES(2);
__le16 cookie; /* TX frame cookie */
__le16 tx_status; /* TX status */
struct bcm43xx_plcp_hdr6 rts_plcp; /* RTS PLCP */
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct bcm43xx_plcp_hdr6 plcp; /* Main PLCP */
} __attribute__((__packed__));
/* MAC TX control */
#define BCM43xx_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
#define BCM43xx_TX4_MAC_KEYIDX_SHIFT 20
#define BCM43xx_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
#define BCM43xx_TX4_MAC_KEYALG_SHIFT 16
#define BCM43xx_TX4_MAC_LIFETIME 0x00001000
#define BCM43xx_TX4_MAC_FRAMEBURST 0x00000800
#define BCM43xx_TX4_MAC_SENDCTS 0x00000400
#define BCM43xx_TX4_MAC_AMPDU 0x00000300
#define BCM43xx_TX4_MAC_AMPDU_SHIFT 8
#define BCM43xx_TX4_MAC_5GHZ 0x00000080
#define BCM43xx_TX4_MAC_IGNPMQ 0x00000020
#define BCM43xx_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */
#define BCM43xx_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
#define BCM43xx_TX4_MAC_SENDRTS 0x00000004
#define BCM43xx_TX4_MAC_LONGFRAME 0x00000002
#define BCM43xx_TX4_MAC_ACK 0x00000001
/* Extra Frame Types */
#define BCM43xx_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */
#define BCM43xx_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
#define BCM43xx_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
/* PHY TX control word */
#define BCM43xx_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
#define BCM43xx_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
#define BCM43xx_TX4_PHY_ANT 0x03C0 /* Antenna selection */
#define BCM43xx_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
#define BCM43xx_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
#define BCM43xx_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
void bcm43xx_generate_txhdr(struct bcm43xx_wldev *dev,
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl,
u16 cookie);
/* Transmit Status */
struct bcm43xx_txstatus {
u16 cookie; /* The cookie from the txhdr */
u16 seq; /* Sequence number */
u8 phy_stat; /* PHY TX status */
u8 frame_count; /* Frame transmit count */
u8 rts_count; /* RTS transmit count */
u8 supp_reason; /* Suppression reason */
/* flags */
u8 pm_indicated; /* PM mode indicated to AP */
u8 intermediate; /* Intermediate status notification (not final) */
u8 for_ampdu; /* Status is for an AMPDU (afterburner) */
u8 acked; /* Wireless ACK received */
};
/* txstatus supp_reason values */
enum {
BCM43xx_TXST_SUPP_NONE, /* Not suppressed */
BCM43xx_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */
BCM43xx_TXST_SUPP_FLUSH, /* Suppressed due to flush request */
BCM43xx_TXST_SUPP_PREV, /* Previous fragment failed */
BCM43xx_TXST_SUPP_CHAN, /* Channel mismatch */
BCM43xx_TXST_SUPP_LIFE, /* Lifetime expired */
BCM43xx_TXST_SUPP_UNDER, /* Buffer underflow */
BCM43xx_TXST_SUPP_ABNACK, /* Afterburner NACK */
};
/* Transmit Status as received through DMA/PIO on old chips */
struct bcm43xx_hwtxstatus {
PAD_BYTES(4);
__le16 cookie;
u8 flags;
u8 count;
PAD_BYTES(2);
__le16 seq;
u8 phy_stat;
PAD_BYTES(1);
} __attribute__((__packed__));
/* Receive header for v4 firmware. */
struct bcm43xx_rxhdr_fw4 {
__le16 frame_len; /* Frame length */
PAD_BYTES(2);
__le16 phy_status0; /* PHY RX Status 0 */
__u8 jssi; /* PHY RX Status 1: JSSI */
__u8 sig_qual; /* PHY RX Status 1: Signal Quality */
__le16 phy_status2; /* PHY RX Status 2 */
__le16 phy_status3; /* PHY RX Status 3 */
__le32 mac_status; /* MAC RX status */
__le16 mac_time;
__le16 channel;
} __attribute__((__packed__));
/* PHY RX Status 0 */
#define BCM43xx_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
#define BCM43xx_RX_PHYST0_PLCPHCF 0x0200
#define BCM43xx_RX_PHYST0_PLCPFV 0x0100
#define BCM43xx_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */
#define BCM43xx_RX_PHYST0_LCRS 0x0040
#define BCM43xx_RX_PHYST0_ANT 0x0020 /* Antenna */
#define BCM43xx_RX_PHYST0_UNSRATE 0x0010
#define BCM43xx_RX_PHYST0_CLIP 0x000C
#define BCM43xx_RX_PHYST0_CLIP_SHIFT 2
#define BCM43xx_RX_PHYST0_FTYPE 0x0003 /* Frame type */
#define BCM43xx_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
#define BCM43xx_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
#define BCM43xx_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
#define BCM43xx_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
/* PHY RX Status 2 */
#define BCM43xx_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
#define BCM43xx_RX_PHYST2_LNAG_SHIFT 14
#define BCM43xx_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
#define BCM43xx_RX_PHYST2_PNAG_SHIFT 10
#define BCM43xx_RX_PHYST2_FOFF 0x03FF /* F offset */
/* PHY RX Status 3 */
#define BCM43xx_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
#define BCM43xx_RX_PHYST3_DIGG_SHIFT 11
#define BCM43xx_RX_PHYST3_TRSTATE 0x0400 /* TR state */
/* MAC RX Status */
#define BCM43xx_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
#define BCM43xx_RX_MAC_KEYIDX 0x000007E0 /* Key index */
#define BCM43xx_RX_MAC_KEYIDX_SHIFT 5
#define BCM43xx_RX_MAC_DECERR 0x00000010 /* Decrypt error */
#define BCM43xx_RX_MAC_DEC 0x00000008 /* Decryption attempted */
#define BCM43xx_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
#define BCM43xx_RX_MAC_RESP 0x00000002 /* Response frame transmitted */
#define BCM43xx_RX_MAC_FCSERR 0x00000001 /* FCS error */
/* RX channel */
#define BCM43xx_RX_CHAN_GAIN 0xFC00 /* Gain */
#define BCM43xx_RX_CHAN_GAIN_SHIFT 10
#define BCM43xx_RX_CHAN_ID 0x03FC /* Channel ID */
#define BCM43xx_RX_CHAN_ID_SHIFT 2
#define BCM43xx_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate);
u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate);
void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
const u16 octets, const u8 bitrate);
void bcm43xx_rx(struct bcm43xx_wldev *dev,
struct sk_buff *skb,
const void *_rxhdr);
void bcm43xx_handle_txstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_txstatus *status);
void bcm43xx_handle_hwtxstatus(struct bcm43xx_wldev *dev,
const struct bcm43xx_hwtxstatus *hw);
/* Helper functions for converting the key-table index from "firmware-format"
* to "raw-format" and back. The firmware API changed for this at some revision.
* We need to account for that here. */
static inline
int bcm43xx_new_kidx_api(struct bcm43xx_wldev *dev)
{
/* FIXME: Not sure the change was at rev 351 */
return (dev->fw.rev >= 351);
}
static inline
u8 bcm43xx_kidx_to_fw(struct bcm43xx_wldev *dev, u8 raw_kidx)
{
u8 firmware_kidx;
if (bcm43xx_new_kidx_api(dev)) {
firmware_kidx = raw_kidx;
} else {
if (raw_kidx >= 4) /* Is per STA key? */
firmware_kidx = raw_kidx - 4;
else
firmware_kidx = raw_kidx; /* TX default key */
}
return firmware_kidx;
}
static inline
u8 bcm43xx_kidx_to_raw(struct bcm43xx_wldev *dev, u8 firmware_kidx)
{
u8 raw_kidx;
if (bcm43xx_new_kidx_api(dev))
raw_kidx = firmware_kidx;
else
raw_kidx = firmware_kidx + 4; /* RX default keys or per STA keys */
return raw_kidx;
}
#endif /* BCM43xx_XMIT_H_ */