summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/Kconfig84
-rw-r--r--drivers/net/wireless/airo.c3
-rw-r--r--drivers/net/wireless/at76c50x-usb.c10
-rw-r--r--drivers/net/wireless/ath/Kconfig8
-rw-r--r--drivers/net/wireless/ath/Makefile9
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h6
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.c3
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.h1
-rw-r--r--drivers/net/wireless/ath/ar9170/hw.h6
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c15
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c41
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c99
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c12
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.h2
-rw-r--r--drivers/net/wireless/ath/ath.h41
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h53
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c33
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c116
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h12
-rw-r--r--drivers/net/wireless/ath/ath5k/initvals.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c193
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c185
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h19
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig8
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile27
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c141
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h73
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c112
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c383
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h64
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c419
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c55
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h36
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c90
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c97
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c183
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c595
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h63
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h72
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c162
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h11
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c841
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c37
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.c50
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c62
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c115
-rw-r--r--drivers/net/wireless/ath/debug.c32
-rw-r--r--drivers/net/wireless/ath/debug.h77
-rw-r--r--drivers/net/wireless/ath/hw.c126
-rw-r--r--drivers/net/wireless/ath/reg.h27
-rw-r--r--drivers/net/wireless/ath/regd.h8
-rw-r--r--drivers/net/wireless/ath/regd_common.h32
-rw-r--r--drivers/net/wireless/b43/b43.h16
-rw-r--r--drivers/net/wireless/b43/main.c4
-rw-r--r--drivers/net/wireless/b43/phy_lp.c6
-rw-r--r--drivers/net/wireless/b43/pio.c79
-rw-r--r--drivers/net/wireless/b43/xmit.c7
-rw-r--r--drivers/net/wireless/b43legacy/main.c4
-rw-r--r--drivers/net/wireless/hostap/Kconfig2
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig7
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c1
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig28
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c50
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c371
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c286
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c233
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c336
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c369
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-led.c85
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-led.h32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c570
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h101
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c278
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c75
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h91
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c469
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h55
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c693
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h113
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h178
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c53
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c323
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h46
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c232
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c177
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c62
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c71
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c294
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c47
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c31
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h70
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c9
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h6
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c48
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c84
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h5
-rw-r--r--drivers/net/wireless/libertas/11d.c696
-rw-r--r--drivers/net/wireless/libertas/11d.h105
-rw-r--r--drivers/net/wireless/libertas/Kconfig39
-rw-r--r--drivers/net/wireless/libertas/Makefile14
-rw-r--r--drivers/net/wireless/libertas/README26
-rw-r--r--drivers/net/wireless/libertas/assoc.c445
-rw-r--r--drivers/net/wireless/libertas/assoc.h141
-rw-r--r--drivers/net/wireless/libertas/cfg.c198
-rw-r--r--drivers/net/wireless/libertas/cfg.h16
-rw-r--r--drivers/net/wireless/libertas/cmd.c538
-rw-r--r--drivers/net/wireless/libertas/cmd.h127
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c116
-rw-r--r--drivers/net/wireless/libertas/debugfs.c27
-rw-r--r--drivers/net/wireless/libertas/decl.h59
-rw-r--r--drivers/net/wireless/libertas/defs.h3
-rw-r--r--drivers/net/wireless/libertas/dev.h419
-rw-r--r--drivers/net/wireless/libertas/host.h959
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h800
-rw-r--r--drivers/net/wireless/libertas/if_cs.c3
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c56
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h3
-rw-r--r--drivers/net/wireless/libertas/if_spi.c3
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/main.c373
-rw-r--r--drivers/net/wireless/libertas/persistcfg.c8
-rw-r--r--drivers/net/wireless/libertas/rx.c2
-rw-r--r--drivers/net/wireless/libertas/scan.c250
-rw-r--r--drivers/net/wireless/libertas/scan.h30
-rw-r--r--drivers/net/wireless/libertas/tx.c2
-rw-r--r--drivers/net/wireless/libertas/types.h4
-rw-r--r--drivers/net/wireless/libertas/wext.c196
-rw-r--r--drivers/net/wireless/libertas/wext.h8
-rw-r--r--drivers/net/wireless/orinoco/Kconfig4
-rw-r--r--drivers/net/wireless/orinoco/hw.c33
-rw-r--r--drivers/net/wireless/orinoco/hw.h3
-rw-r--r--drivers/net/wireless/orinoco/main.c34
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h1
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig30
-rw-r--r--drivers/net/wireless/rt2x00/Makefile2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c3323
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.h1960
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h7
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.c159
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.h52
-rw-r--r--drivers/net/wireless/strip.c17
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c7
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h92
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.c369
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h586
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.c215
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.h22
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c329
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h115
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_conf.h911
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c64
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.c155
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.h53
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c963
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c68
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_reg.h47
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.c86
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c311
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.h65
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c76
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h18
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h18
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c202
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h25
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c4
200 files changed, 18341 insertions, 9212 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index d7a764a2fc1..85f8bf4112c 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -5,6 +5,7 @@
menuconfig WLAN
bool "Wireless LAN"
depends on !S390
+ select WIRELESS
default y
---help---
This section contains all the pre 802.11 and 802.11 wireless
@@ -67,6 +68,8 @@ config WAVELAN
tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support"
depends on ISA && WLAN_PRE80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
---help---
The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
a Radio LAN (wireless Ethernet-like Local Area Network) using the
@@ -90,6 +93,8 @@ config PCMCIA_WAVELAN
tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support"
depends on PCMCIA && WLAN_PRE80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
help
Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA
(PC-card) wireless Ethernet networking card to your computer. This
@@ -102,6 +107,7 @@ config PCMCIA_NETWAVE
tristate "Xircom Netwave AirSurfer Pcmcia wireless support"
depends on PCMCIA && WLAN_PRE80211
select WIRELESS_EXT
+ select WEXT_PRIV
help
Say Y here if you intend to attach this type of PCMCIA (PC-card)
wireless Ethernet networking card to your computer.
@@ -123,6 +129,8 @@ config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"
depends on PCMCIA && WLAN_80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
---help---
Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
(PC-card) wireless Ethernet networking card to your computer.
@@ -132,46 +140,6 @@ config PCMCIA_RAYCS
To compile this driver as a module, choose M here: the module will be
called ray_cs. If unsure, say N.
-config LIBERTAS
- tristate "Marvell 8xxx Libertas WLAN driver support"
- depends on WLAN_80211
- select WIRELESS_EXT
- select LIB80211
- select FW_LOADER
- ---help---
- A library for Marvell Libertas 8xxx devices.
-
-config LIBERTAS_USB
- tristate "Marvell Libertas 8388 USB 802.11b/g cards"
- depends on LIBERTAS && USB
- ---help---
- A driver for Marvell Libertas 8388 USB devices.
-
-config LIBERTAS_CS
- tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
- depends on LIBERTAS && PCMCIA
- select FW_LOADER
- ---help---
- A driver for Marvell Libertas 8385 CompactFlash devices.
-
-config LIBERTAS_SDIO
- tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
- depends on LIBERTAS && MMC
- ---help---
- A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
-
-config LIBERTAS_SPI
- tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
- depends on LIBERTAS && SPI
- ---help---
- A driver for Marvell Libertas 8686 SPI devices.
-
-config LIBERTAS_DEBUG
- bool "Enable full debugging output in the Libertas module."
- depends on LIBERTAS
- ---help---
- Debugging support.
-
config LIBERTAS_THINFIRM
tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware"
depends on WLAN_80211 && MAC80211
@@ -190,6 +158,8 @@ config AIRO
depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN)
select WIRELESS_EXT
select CRYPTO
+ select WEXT_SPY
+ select WEXT_PRIV
---help---
This is the standard Linux driver to support Cisco/Aironet ISA and
PCI 802.11 wireless cards.
@@ -207,6 +177,7 @@ config ATMEL
tristate "Atmel at76c50x chipset 802.11b support"
depends on (PCI || PCMCIA) && WLAN_80211
select WIRELESS_EXT
+ select WEXT_PRIV
select FW_LOADER
select CRC32
---help---
@@ -266,18 +237,21 @@ config AIRO_CS
Cisco Linux utilities can be used to configure the card.
config PCMCIA_WL3501
- tristate "Planet WL3501 PCMCIA cards"
- depends on EXPERIMENTAL && PCMCIA && WLAN_80211
- select WIRELESS_EXT
- ---help---
- A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
- It has basic support for Linux wireless extensions and initial
- micro support for ethtool.
+ tristate "Planet WL3501 PCMCIA cards"
+ depends on EXPERIMENTAL && PCMCIA && WLAN_80211
+ select WIRELESS_EXT
+ select WEXT_SPY
+ help
+ A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
+ It has basic support for Linux wireless extensions and initial
+ micro support for ethtool.
config PRISM54
tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)'
depends on PCI && EXPERIMENTAL && WLAN_80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
---help---
This enables support for FullMAC PCI/Cardbus prism54 devices. This
@@ -300,6 +274,7 @@ config USB_ZD1201
tristate "USB ZD1201 based Wireless device support"
depends on USB && WLAN_80211
select WIRELESS_EXT
+ select WEXT_PRIV
select FW_LOADER
---help---
Say Y if you want to use wireless LAN adapters based on the ZyDAS
@@ -476,17 +451,18 @@ config MWL8K
To compile this driver as a module, choose M here: the module
will be called mwl8k. If unsure, say N.
-source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/ath/Kconfig"
-source "drivers/net/wireless/ipw2x00/Kconfig"
-source "drivers/net/wireless/iwlwifi/Kconfig"
-source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
-source "drivers/net/wireless/zd1211rw/Kconfig"
-source "drivers/net/wireless/rt2x00/Kconfig"
+source "drivers/net/wireless/hostap/Kconfig"
+source "drivers/net/wireless/ipw2x00/Kconfig"
+source "drivers/net/wireless/iwlwifi/Kconfig"
+source "drivers/net/wireless/iwmc3200wifi/Kconfig"
+source "drivers/net/wireless/libertas/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
+source "drivers/net/wireless/p54/Kconfig"
+source "drivers/net/wireless/rt2x00/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
-source "drivers/net/wireless/iwmc3200wifi/Kconfig"
+source "drivers/net/wireless/zd1211rw/Kconfig"
endif # WLAN
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index abf896a7390..4eec87c3be2 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -5659,7 +5659,8 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
pci_save_state(pdev);
- return pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
}
static int airo_pci_resume(struct pci_dev *pdev)
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 8e1a55dec35..e559dc96055 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2217,6 +2217,8 @@ static struct ieee80211_supported_band at76_supported_band = {
static int at76_init_new_device(struct at76_priv *priv,
struct usb_interface *interface)
{
+ struct wiphy *wiphy;
+ size_t len;
int ret;
/* set up the endpoint information */
@@ -2254,6 +2256,7 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->device_unplugged = 0;
/* mac80211 initialisation */
+ wiphy = priv->hw->wiphy;
priv->hw->wiphy->max_scan_ssids = 1;
priv->hw->wiphy->max_scan_ie_len = 0;
priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
@@ -2265,6 +2268,13 @@ static int at76_init_new_device(struct at76_priv *priv,
SET_IEEE80211_DEV(priv->hw, &interface->dev);
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ len = sizeof(wiphy->fw_version);
+ snprintf(wiphy->fw_version, len, "%d.%d.%d-%d",
+ priv->fw_version.major, priv->fw_version.minor,
+ priv->fw_version.patch, priv->fw_version.build);
+
+ wiphy->hw_version = priv->board_type;
+
ret = ieee80211_register_hw(priv->hw);
if (ret) {
printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index 11ded150b93..6ce86cb3765 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -16,7 +16,15 @@ menuconfig ATH_COMMON
http://wireless.kernel.org/en/users/Drivers/Atheros
if ATH_COMMON
+
+config ATH_DEBUG
+ bool "Atheros wireless debugging"
+ ---help---
+ Say Y, if you want to debug atheros wireless drivers.
+ Right now only ath9k makes use of this.
+
source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig"
source "drivers/net/wireless/ath/ar9170/Kconfig"
+
endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 4bb0132ada3..8113a5042af 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,6 +1,11 @@
obj-$(CONFIG_ATH5K) += ath5k/
-obj-$(CONFIG_ATH9K) += ath9k/
+obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_AR9170_USB) += ar9170/
obj-$(CONFIG_ATH_COMMON) += ath.o
-ath-objs := main.o regd.o
+
+ath-objs := main.o \
+ regd.o \
+ hw.o
+
+ath-$(CONFIG_ATH_DEBUG) += debug.o
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index 914e4718a9a..9f9459860d8 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -172,8 +172,6 @@ struct ar9170 {
/* interface mode settings */
struct ieee80211_vif *vif;
- u8 mac_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
/* beaconing */
struct sk_buff *beacon;
@@ -204,6 +202,8 @@ struct ar9170 {
u8 power_2G_ht20[8];
u8 power_2G_ht40[8];
+ u8 phy_heavy_clip;
+
#ifdef CONFIG_AR9170_LEDS
struct delayed_work led_work;
struct ar9170_led leds[AR9170_NUM_LEDS];
@@ -231,7 +231,7 @@ struct ar9170 {
struct sk_buff_head tx_status_ampdu;
spinlock_t tx_ampdu_list_lock;
struct list_head tx_ampdu_list;
- unsigned int tx_ampdu_pending;
+ atomic_t tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
index f57a6200167..cf6f5c4174a 100644
--- a/drivers/net/wireless/ath/ar9170/cmd.c
+++ b/drivers/net/wireless/ath/ar9170/cmd.c
@@ -72,8 +72,7 @@ int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
return err;
}
-static int ar9170_read_mreg(struct ar9170 *ar, int nregs,
- const u32 *regs, u32 *out)
+int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out)
{
int i, err;
__le32 *offs, *res;
diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h
index a4f0e50e52b..826c45e6b27 100644
--- a/drivers/net/wireless/ath/ar9170/cmd.h
+++ b/drivers/net/wireless/ath/ar9170/cmd.h
@@ -44,6 +44,7 @@
int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len);
int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val);
+int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out);
int ar9170_echo_test(struct ar9170 *ar, u32 v);
/*
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
index 6cbfb2f8339..701ddb7d840 100644
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ b/drivers/net/wireless/ath/ar9170/hw.h
@@ -152,14 +152,14 @@ enum ar9170_cmd {
#define AR9170_MAC_REG_FTF_BIT14 BIT(14)
#define AR9170_MAC_REG_FTF_BIT15 BIT(15)
#define AR9170_MAC_REG_FTF_BAR BIT(24)
-#define AR9170_MAC_REG_FTF_BIT25 BIT(25)
+#define AR9170_MAC_REG_FTF_BA BIT(25)
#define AR9170_MAC_REG_FTF_PSPOLL BIT(26)
#define AR9170_MAC_REG_FTF_RTS BIT(27)
#define AR9170_MAC_REG_FTF_CTS BIT(28)
#define AR9170_MAC_REG_FTF_ACK BIT(29)
#define AR9170_MAC_REG_FTF_CFE BIT(30)
#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31)
-#define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff
+#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff
#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff
#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0)
@@ -311,6 +311,8 @@ struct ar9170_tx_control {
#define AR9170_TX_PHY_SHORT_GI 0x80000000
+#define AR5416_MAX_RATE_POWER 63
+
struct ar9170_rx_head {
u8 plcp[12];
} __packed;
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
index 614e3218a2b..ddc8c09dc79 100644
--- a/drivers/net/wireless/ath/ar9170/mac.c
+++ b/drivers/net/wireless/ath/ar9170/mac.c
@@ -35,6 +35,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+
+#include <asm/unaligned.h>
+
#include "ar9170.h"
#include "cmd.h"
@@ -227,11 +230,8 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac)
ar9170_regwrite_begin(ar);
- ar9170_regwrite(reg,
- (mac[3] << 24) | (mac[2] << 16) |
- (mac[1] << 8) | mac[0]);
-
- ar9170_regwrite(reg + 4, (mac[5] << 8) | mac[4]);
+ ar9170_regwrite(reg, get_unaligned_le32(mac));
+ ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4));
ar9170_regwrite_finish();
@@ -311,13 +311,14 @@ static int ar9170_set_promiscouous(struct ar9170 *ar)
int ar9170_set_operating_mode(struct ar9170 *ar)
{
+ struct ath_common *common = &ar->common;
u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS;
u8 *mac_addr, *bssid;
int err;
if (ar->vif) {
- mac_addr = ar->mac_addr;
- bssid = ar->bssid;
+ mac_addr = common->macaddr;
+ bssid = common->curbssid;
switch (ar->vif->type) {
case NL80211_IFTYPE_MESH_POINT:
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index c1f8c69db16..7e59b82e64d 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -414,9 +414,9 @@ static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
skb_queue_tail(&ar->tx_status_ampdu, skb);
ar9170_tx_fake_ampdu_status(ar);
- ar->tx_ampdu_pending--;
- if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+ if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
+ !list_empty(&ar->tx_ampdu_list))
ar9170_tx_ampdu(ar);
}
@@ -1248,6 +1248,7 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
ar->global_ampdu_density = 6;
ar->global_ampdu_factor = 3;
+ atomic_set(&ar->tx_ampdu_pending, 0);
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1773,7 +1774,7 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_TX_TIMEOUT);
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
- ar->tx_ampdu_pending++;
+ atomic_inc(&ar->tx_ampdu_pending);
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
@@ -1784,7 +1785,7 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
- ar->tx_ampdu_pending--;
+ atomic_dec(&ar->tx_ampdu_pending);
frames_failed++;
dev_kfree_skb_any(skb);
@@ -1931,7 +1932,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
bool run = ar9170_tx_ampdu_queue(ar, skb);
- if (run || !ar->tx_ampdu_pending)
+ if (run || !atomic_read(&ar->tx_ampdu_pending))
ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
@@ -1952,6 +1953,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct ar9170 *ar = hw->priv;
+ struct ath_common *common = &ar->common;
int err = 0;
mutex_lock(&ar->mutex);
@@ -1962,7 +1964,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
}
ar->vif = conf->vif;
- memcpy(ar->mac_addr, conf->mac_addr, ETH_ALEN);
+ memcpy(common->macaddr, conf->mac_addr, ETH_ALEN);
if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
ar->rx_software_decryption = true;
@@ -2131,12 +2133,13 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
u32 changed)
{
struct ar9170 *ar = hw->priv;
+ struct ath_common *common = &ar->common;
int err = 0;
mutex_lock(&ar->mutex);
if (changed & BSS_CHANGED_BSSID) {
- memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN);
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
err = ar9170_set_operating_mode(ar);
if (err)
goto out;
@@ -2190,22 +2193,30 @@ static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw)
{
struct ar9170 *ar = hw->priv;
int err;
- u32 tsf_low;
- u32 tsf_high;
u64 tsf;
+#define NR 3
+ static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H,
+ AR9170_MAC_REG_TSF_L,
+ AR9170_MAC_REG_TSF_H };
+ u32 val[NR];
+ int loops = 0;
mutex_lock(&ar->mutex);
- err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_L, &tsf_low);
- if (!err)
- err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_H, &tsf_high);
+
+ while (loops++ < 10) {
+ err = ar9170_read_mreg(ar, NR, addr, val);
+ if (err || val[0] == val[2])
+ break;
+ }
+
mutex_unlock(&ar->mutex);
if (WARN_ON(err))
return 0;
-
- tsf = tsf_high;
- tsf = (tsf << 32) | tsf_low;
+ tsf = val[0];
+ tsf = (tsf << 32) | val[1];
return tsf;
+#undef NR
}
static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index dbd488da18b..45a415ea809 100644
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
@@ -1239,9 +1239,6 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
struct ar9170_calctl_edges edges[],
u32 freq)
{
-/* TODO: move somewhere else */
-#define AR5416_MAX_RATE_POWER 63
-
int i;
u8 rc = AR5416_MAX_RATE_POWER;
u8 f;
@@ -1259,10 +1256,11 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
break;
}
if (i > 0 && f < edges[i].channel) {
- if (f > edges[i-1].channel &&
- edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
+ if (f > edges[i - 1].channel &&
+ edges[i - 1].power_flags &
+ AR9170_CALCTL_EDGE_FLAGS) {
/* lower channel has the inband flag set */
- rc = edges[i-1].power_flags &
+ rc = edges[i - 1].power_flags &
~AR9170_CALCTL_EDGE_FLAGS;
}
break;
@@ -1270,18 +1268,48 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
}
if (i == AR5416_NUM_BAND_EDGES) {
- if (f > edges[i-1].channel &&
- edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
+ if (f > edges[i - 1].channel &&
+ edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
/* lower channel has the inband flag set */
- rc = edges[i-1].power_flags &
+ rc = edges[i - 1].power_flags &
~AR9170_CALCTL_EDGE_FLAGS;
}
}
return rc;
}
-/* calculate the conformance test limits and apply them to ar->power*
- * (derived from otus hal/hpmain.c, line 3706 ff.)
+static u8 ar9170_get_heavy_clip(struct ar9170 *ar,
+ struct ar9170_calctl_edges edges[],
+ u32 freq, enum ar9170_bw bw)
+{
+ u8 f;
+ int i;
+ u8 rc = 0;
+
+ if (freq < 3000)
+ f = freq - 2300;
+ else
+ f = (freq - 4800) / 5;
+
+ if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE)
+ rc |= 0xf0;
+
+ for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
+ if (edges[i].channel == 0xff)
+ break;
+ if (f == edges[i].channel) {
+ if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS))
+ rc |= 0x0f;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * calculate the conformance test limits and the heavy clip parameter
+ * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706)
*/
static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
{
@@ -1295,7 +1323,8 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
int pwr_cal_len;
} *modes;
- /* order is relevant in the mode_list_*: we fall back to the
+ /*
+ * order is relevant in the mode_list_*: we fall back to the
* lower indices if any mode is missed in the EEPROM.
*/
struct ctl_modes mode_list_2ghz[] = {
@@ -1313,7 +1342,10 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])
- /* TODO: investigate the differences between OTUS'
+ ar->phy_heavy_clip = 0;
+
+ /*
+ * TODO: investigate the differences between OTUS'
* hpreg.c::zfHpGetRegulatoryDomain() and
* ath/regd.c::ath_regd_get_band_ctl() -
* e.g. for FCC3_WORLD the OTUS procedure
@@ -1347,6 +1379,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
if (ctl_idx < AR5416_NUM_CTLS) {
int f_off = 0;
+ /* determine heav clip parameter from
+ the 11G edges array */
+ if (modes[i].ctl_mode == CTL_11G) {
+ ar->phy_heavy_clip =
+ ar9170_get_heavy_clip(ar,
+ EDGES(ctl_idx, 1),
+ freq, bw);
+ }
+
/* adjust freq for 40MHz */
if (modes[i].ctl_mode == CTL_2GHT40 ||
modes[i].ctl_mode == CTL_5GHT40) {
@@ -1360,13 +1401,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1),
freq+f_off);
- /* TODO: check if the regulatory max. power is
+ /*
+ * TODO: check if the regulatory max. power is
* controlled by cfg80211 for DFS
* (hpmain applies it to max_power itself for DFS freq)
*/
} else {
- /* Workaround in otus driver, hpmain.c, line 3906:
+ /*
+ * Workaround in otus driver, hpmain.c, line 3906:
* if no data for 5GHT20 are found, take the
* legacy 5G value.
* We extend this here to fallback from any other *HT or
@@ -1390,6 +1433,19 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
modes[i].max_power);
}
}
+
+ if (ar->phy_heavy_clip & 0xf0) {
+ ar->power_2G_ht40[0]--;
+ ar->power_2G_ht40[1]--;
+ ar->power_2G_ht40[2]--;
+ }
+ if (ar->phy_heavy_clip & 0xf) {
+ ar->power_2G_ht20[0]++;
+ ar->power_2G_ht20[1]++;
+ ar->power_2G_ht20[2]++;
+ }
+
+
#undef EDGES
}
@@ -1499,8 +1555,6 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
/* calc. conformance test limits and apply to ar->power*[] */
ar9170_calc_ctl(ar, freq, bw);
- /* TODO: (heavy clip) regulatory domain power level fine-tuning. */
-
/* set ACK/CTS TX power */
ar9170_regwrite_begin(ar);
@@ -1643,6 +1697,17 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
if (err)
return err;
+ if (ar->phy_heavy_clip) {
+ err = ar9170_write_reg(ar, 0x1c59e0,
+ 0x200 | ar->phy_heavy_clip);
+ if (err) {
+ if (ar9170_nag_limiter(ar))
+ printk(KERN_ERR "%s: failed to set "
+ "heavy clip\n",
+ wiphy_name(ar->hw->wiphy));
+ }
+ }
+
for (i = 0; i < 2; i++) {
ar->noise[i] = ar9170_calc_noise_dbm(
(le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff);
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index e974e5829e1..6bdcdf6d1cc 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -108,15 +108,15 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
return ;
spin_lock_irqsave(&aru->tx_urb_lock, flags);
- if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) {
+ if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) {
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
}
- aru->tx_submitted_urbs++;
+ atomic_inc(&aru->tx_submitted_urbs);
urb = usb_get_from_anchor(&aru->tx_pending);
if (!urb) {
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
@@ -133,7 +133,7 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
err);
usb_unanchor_urb(urb);
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, urb->context);
}
@@ -151,7 +151,7 @@ static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
return ;
}
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, skb);
@@ -794,7 +794,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
spin_lock_init(&aru->tx_urb_lock);
aru->tx_pending_urbs = 0;
- aru->tx_submitted_urbs = 0;
+ atomic_set(&aru->tx_submitted_urbs, 0);
aru->common.stop = ar9170_usb_stop;
aru->common.flush = ar9170_usb_flush;
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
index d098f4d5d2f..a2ce3b169ce 100644
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ b/drivers/net/wireless/ath/ar9170/usb.h
@@ -67,7 +67,7 @@ struct ar9170_usb {
bool req_one_stage_fw;
spinlock_t tx_urb_lock;
- unsigned int tx_submitted_urbs;
+ atomic_t tx_submitted_urbs;
unsigned int tx_pending_urbs;
struct completion cmd_wait;
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index a63e90cbf9e..5e19a7330d3 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -18,6 +18,15 @@
#define ATH_H
#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <net/mac80211.h>
+
+static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+enum ath_device_state {
+ ATH_HW_UNAVAILABLE,
+ ATH_HW_INITIALIZED,
+};
struct reg_dmn_pair_mapping {
u16 regDmnEnum;
@@ -36,13 +45,45 @@ struct ath_regulatory {
struct reg_dmn_pair_mapping *regpair;
};
+struct ath_ops {
+ unsigned int (*read)(void *, u32 reg_offset);
+ void (*write)(void *, u32 val, u32 reg_offset);
+};
+
+struct ath_common;
+
+struct ath_bus_ops {
+ void (*read_cachesize)(struct ath_common *common, int *csz);
+ void (*cleanup)(struct ath_common *common);
+ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+ void (*bt_coex_prep)(struct ath_common *common);
+};
+
struct ath_common {
+ void *ah;
+ void *priv;
+ struct ieee80211_hw *hw;
+ int debug_mask;
+ enum ath_device_state state;
+
u16 cachelsz;
+ u16 curaid;
+ u8 macaddr[ETH_ALEN];
+ u8 curbssid[ETH_ALEN];
+ u8 bssidmask[ETH_ALEN];
+
+ u8 tx_chainmask;
+ u8 rx_chainmask;
+
struct ath_regulatory regulatory;
+ const struct ath_ops *ops;
+ const struct ath_bus_ops *bus_ops;
};
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
u32 len,
gfp_t gfp_mask);
+void ath_hw_setbssidmask(struct ath_common *common);
+
#endif /* ATH_H */
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6cd5efcec41..6a2a9676111 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -35,6 +35,7 @@
* TODO: Make a more generic struct (eg. add more stuff to ath5k_capabilities)
* and clean up common bits, then introduce set/get functions in eeprom.c */
#include "eeprom.h"
+#include "../ath.h"
/* PCI IDs */
#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */
@@ -165,13 +166,6 @@
#define AR5K_INI_VAL_XR 0
#define AR5K_INI_VAL_MAX 5
-/* Used for BSSID etc manipulation */
-#define AR5K_LOW_ID(_a)( \
-(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \
-)
-
-#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8)
-
/*
* Some tuneable values (these should be changeable by the user)
* TODO: Make use of them and add more options OR use debug/configfs
@@ -204,6 +198,7 @@
#define AR5K_TUNE_CWMAX_11B 1023
#define AR5K_TUNE_CWMAX_XR 7
#define AR5K_TUNE_NOISE_FLOOR -72
+#define AR5K_TUNE_CCA_MAX_GOOD_VALUE -95
#define AR5K_TUNE_MAX_TXPOWER 63
#define AR5K_TUNE_DEFAULT_TXPOWER 25
#define AR5K_TUNE_TPC_TXPOWER false
@@ -1012,6 +1007,14 @@ struct ath5k_capabilities {
} cap_queues;
};
+/* size of noise floor history (keep it a power of two) */
+#define ATH5K_NF_CAL_HIST_MAX 8
+struct ath5k_nfcal_hist
+{
+ s16 index; /* current index into nfval */
+ s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */
+};
+
/***************************************\
HARDWARE ABSTRACTION LAYER STRUCTURE
@@ -1027,6 +1030,7 @@ struct ath5k_capabilities {
/* TODO: Clean up and merge with ath5k_softc */
struct ath5k_hw {
u32 ah_magic;
+ struct ath_common common;
struct ath5k_softc *ah_sc;
void __iomem *ah_iobase;
@@ -1067,14 +1071,6 @@ struct ath5k_hw {
u8 ah_def_ant;
bool ah_software_retry;
- u8 ah_sta_id[ETH_ALEN];
-
- /* Current BSSID we are trying to assoc to / create.
- * This is passed by mac80211 on config_interface() and cached here for
- * use in resets */
- u8 ah_bssid[ETH_ALEN];
- u8 ah_bssid_mask[ETH_ALEN];
-
int ah_gpio_npins;
struct ath5k_capabilities ah_capabilities;
@@ -1125,6 +1121,8 @@ struct ath5k_hw {
struct ieee80211_channel r_last_channel;
} ah_radar;
+ struct ath5k_nfcal_hist ah_nfcal_hist;
+
/* noise floor from last periodic calibration */
s32 ah_noise_floor;
@@ -1160,7 +1158,7 @@ struct ath5k_hw {
*/
/* Attach/Detach Functions */
-extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc);
+extern int ath5k_hw_attach(struct ath5k_softc *sc);
extern void ath5k_hw_detach(struct ath5k_hw *ah);
/* LED functions */
@@ -1203,10 +1201,9 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
/* Protocol Control Unit Functions */
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
/* BSSID Functions */
-extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
-extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
-extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
+extern void ath5k_hw_set_associd(struct ath5k_hw *ah);
+extern void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
/* Receive start/stop functions */
extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
@@ -1288,8 +1285,10 @@ extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
/* PHY calibration */
+void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah);
extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
/* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
@@ -1329,17 +1328,21 @@ static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
return turbo ? (clock / 80) : (clock / 40);
}
-/*
- * Read from a register
- */
+static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
+{
+ return &ah->common;
+}
+
+static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
+{
+ return &(ath5k_hw_common(ah)->regulatory);
+}
+
static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
{
return ioread32(ah->ah_iobase + reg);
}
-/*
- * Write to a register
- */
static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
{
iowrite32(val, ah->ah_iobase + reg);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 71a1bd25451..42284445b75 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -101,25 +101,15 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
* -ENODEV if the device is not supported or prints an error msg if something
* else went wrong.
*/
-struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
+int ath5k_hw_attach(struct ath5k_softc *sc)
{
- struct ath5k_hw *ah;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
struct pci_dev *pdev = sc->pdev;
struct ath5k_eeprom_info *ee;
int ret;
u32 srev;
- /*If we passed the test malloc a ath5k_hw struct*/
- ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
- if (ah == NULL) {
- ret = -ENOMEM;
- ATH5K_ERR(sc, "out of memory\n");
- goto err;
- }
-
- ah->ah_sc = sc;
- ah->ah_iobase = sc->iobase;
-
/*
* HW information
*/
@@ -278,12 +268,12 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
goto err_free;
}
+ ee = &ah->ah_capabilities.cap_eeprom;
+
/*
* Write PCI-E power save settings
*/
if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-
ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
@@ -321,7 +311,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
}
/* Crypto settings */
- ee = &ah->ah_capabilities.cap_eeprom;
ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
!AR5K_EEPROM_AES_DIS(ee->ee_misc5));
@@ -336,20 +325,21 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){});
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
- memset(ah->ah_bssid, 0xff, ETH_ALEN);
- ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+ memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
+ ath5k_hw_set_associd(ah);
ath5k_hw_set_opmode(ah);
ath5k_hw_rfgain_opt_init(ah);
+ ath5k_hw_init_nfcal_hist(ah);
+
/* turn on HW LEDs */
ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
- return ah;
+ return 0;
err_free:
kfree(ah);
-err:
- return ERR_PTR(ret);
+ return ret;
}
/**
@@ -369,5 +359,4 @@ void ath5k_hw_detach(struct ath5k_hw *ah)
ath5k_eeprom_detach(ah);
/* assume interrupts are down */
- kfree(ah);
}
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 9c6ab5378f6..07c1e52b5a0 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -195,12 +195,13 @@ static int __devinit ath5k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void __devexit ath5k_pci_remove(struct pci_dev *pdev);
#ifdef CONFIG_PM
-static int ath5k_pci_suspend(struct pci_dev *pdev,
- pm_message_t state);
-static int ath5k_pci_resume(struct pci_dev *pdev);
+static int ath5k_pci_suspend(struct device *dev);
+static int ath5k_pci_resume(struct device *dev);
+
+SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
+#define ATH5K_PM_OPS (&ath5k_pm_ops)
#else
-#define ath5k_pci_suspend NULL
-#define ath5k_pci_resume NULL
+#define ATH5K_PM_OPS NULL
#endif /* CONFIG_PM */
static struct pci_driver ath5k_pci_driver = {
@@ -208,8 +209,7 @@ static struct pci_driver ath5k_pci_driver = {
.id_table = ath5k_pci_id_table,
.probe = ath5k_pci_probe,
.remove = __devexit_p(ath5k_pci_remove),
- .suspend = ath5k_pci_suspend,
- .resume = ath5k_pci_resume,
+ .driver.pm = ATH5K_PM_OPS,
};
@@ -437,6 +437,22 @@ ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
return name;
}
+static unsigned int ath5k_ioread32(void *hw_priv, u32 reg_offset)
+{
+ struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv;
+ return ath5k_hw_reg_read(ah, reg_offset);
+}
+
+static void ath5k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+{
+ struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv;
+ ath5k_hw_reg_write(ah, val, reg_offset);
+}
+
+static const struct ath_ops ath5k_common_ops = {
+ .read = ath5k_ioread32,
+ .write = ath5k_iowrite32,
+};
static int __devinit
ath5k_pci_probe(struct pci_dev *pdev,
@@ -444,6 +460,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
{
void __iomem *mem;
struct ath5k_softc *sc;
+ struct ath_common *common;
struct ieee80211_hw *hw;
int ret;
u8 csz;
@@ -547,7 +564,6 @@ ath5k_pci_probe(struct pci_dev *pdev,
__set_bit(ATH_STAT_INVALID, sc->status);
sc->iobase = mem; /* So we can unmap it on detach */
- sc->common.cachelsz = csz << 2; /* convert to bytes */
sc->opmode = NL80211_IFTYPE_STATION;
sc->bintval = 1000;
mutex_init(&sc->lock);
@@ -565,13 +581,28 @@ ath5k_pci_probe(struct pci_dev *pdev,
goto err_free;
}
- /* Initialize device */
- sc->ah = ath5k_hw_attach(sc);
- if (IS_ERR(sc->ah)) {
- ret = PTR_ERR(sc->ah);
+ /*If we passed the test malloc a ath5k_hw struct*/
+ sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
+ if (!sc->ah) {
+ ret = -ENOMEM;
+ ATH5K_ERR(sc, "out of memory\n");
goto err_irq;
}
+ sc->ah->ah_sc = sc;
+ sc->ah->ah_iobase = sc->iobase;
+ common = ath5k_hw_common(sc->ah);
+ common->ops = &ath5k_common_ops;
+ common->ah = sc->ah;
+ common->hw = hw;
+ common->cachelsz = csz << 2; /* convert to bytes */
+
+ /* Initialize device */
+ ret = ath5k_hw_attach(sc);
+ if (ret) {
+ goto err_free_ah;
+ }
+
/* set up multi-rate retry capabilities */
if (sc->ah->ah_version == AR5K_AR5212) {
hw->max_rates = 4;
@@ -640,6 +671,8 @@ err_ah:
ath5k_hw_detach(sc->ah);
err_irq:
free_irq(pdev->irq, sc);
+err_free_ah:
+ kfree(sc->ah);
err_free:
ieee80211_free_hw(hw);
err_map:
@@ -661,6 +694,7 @@ ath5k_pci_remove(struct pci_dev *pdev)
ath5k_debug_finish_device(sc);
ath5k_detach(pdev, hw);
ath5k_hw_detach(sc->ah);
+ kfree(sc->ah);
free_irq(pdev->irq, sc);
pci_iounmap(pdev, sc->iobase);
pci_release_region(pdev, 0);
@@ -669,33 +703,20 @@ ath5k_pci_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
-static int
-ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int ath5k_pci_suspend(struct device *dev)
{
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev));
struct ath5k_softc *sc = hw->priv;
ath5k_led_off(sc);
-
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
return 0;
}
-static int
-ath5k_pci_resume(struct pci_dev *pdev)
+static int ath5k_pci_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath5k_softc *sc = hw->priv;
- int err;
-
- pci_restore_state(pdev);
-
- err = pci_enable_device(pdev);
- if (err)
- return err;
/*
* Suspend/Resume resets the PCI configuration space, so we have to
@@ -718,7 +739,7 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath5k_softc *sc = hw->priv;
- struct ath_regulatory *regulatory = &sc->common.regulatory;
+ struct ath_regulatory *regulatory = ath5k_hw_regulatory(sc->ah);
return ath_reg_notifier_apply(wiphy, request, regulatory);
}
@@ -728,7 +749,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
- struct ath_regulatory *regulatory = &sc->common.regulatory;
+ struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
u8 mac[ETH_ALEN] = {};
int ret;
@@ -815,7 +836,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
SET_IEEE80211_PERM_ADDR(hw, mac);
/* All MAC address bits matter for ACKs */
- memset(sc->bssidmask, 0xff, ETH_ALEN);
+ memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
@@ -1153,19 +1174,20 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
static
struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
{
+ struct ath_common *common = ath5k_hw_common(sc->ah);
struct sk_buff *skb;
/*
* Allocate buffer with headroom_needed space for the
* fake physical layer header at the start.
*/
- skb = ath_rxbuf_alloc(&sc->common,
- sc->rxbufsize + sc->common.cachelsz - 1,
+ skb = ath_rxbuf_alloc(common,
+ sc->rxbufsize + common->cachelsz - 1,
GFP_ATOMIC);
if (!skb) {
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
- sc->rxbufsize + sc->common.cachelsz - 1);
+ sc->rxbufsize + common->cachelsz - 1);
return NULL;
}
@@ -1606,13 +1628,14 @@ static int
ath5k_rx_start(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
struct ath5k_buf *bf;
int ret;
- sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
+ sc->rxbufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
- sc->common.cachelsz, sc->rxbufsize);
+ common->cachelsz, sc->rxbufsize);
spin_lock_bh(&sc->rxbuflock);
sc->rxlink = NULL;
@@ -1685,13 +1708,14 @@ static void
ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
struct ieee80211_rx_status *rxs)
{
+ struct ath_common *common = ath5k_hw_common(sc->ah);
u64 tsf, bc_tstamp;
u32 hw_tu;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
if (ieee80211_is_beacon(mgmt->frame_control) &&
le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
- memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
+ memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) {
/*
* Received an IBSS beacon with the same BSSID. Hardware *must*
* have updated the local TSF. We have to work around various
@@ -3177,6 +3201,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
unsigned long flags;
mutex_lock(&sc->lock);
@@ -3185,10 +3210,9 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
if (changes & BSS_CHANGED_BSSID) {
/* Cache for later use during resets */
- memcpy(ah->ah_bssid, bss_conf->bssid, ETH_ALEN);
- /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
- * a clean way of letting us retrieve this yet. */
- ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ common->curaid = 0;
+ ath5k_hw_set_associd(ah);
mmiowb();
}
@@ -3201,6 +3225,14 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
set_beacon_filter(hw, sc->assoc);
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
AR5K_LED_ASSOC : AR5K_LED_INIT);
+ if (bss_conf->assoc) {
+ ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
+ common->curaid = bss_conf->aid;
+ ath5k_hw_set_associd(ah);
+ /* Once ANI is available you would start it here */
+ }
}
if (changes & BSS_CHANGED_BEACON) {
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index a28c42f32c9..b14ba07e915 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -115,7 +115,6 @@ struct ath5k_rfkill {
* associated with an instance of a device */
struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
- struct ath_common common;
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
@@ -202,15 +201,4 @@ struct ath5k_softc {
#define ath5k_hw_hasveol(_ah) \
(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
-static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
-{
- return &ah->ah_sc->common;
-}
-
-static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
-{
- return &(ath5k_hw_common(ah)->regulatory);
-
-}
-
#endif
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
index 18eb5190ce4..8fa43930882 100644
--- a/drivers/net/wireless/ath/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -560,8 +560,8 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
{ AR5K_SLEEP0, 0x0002aaaa },
{ AR5K_SLEEP1, 0x02005555 },
{ AR5K_SLEEP2, 0x00000000 },
- { AR5K_BSS_IDM0, 0xffffffff },
- { AR5K_BSS_IDM1, 0x0000ffff },
+ { AR_BSSMSKL, 0xffffffff },
+ { AR_BSSMSKU, 0x0000ffff },
{ AR5K_TXPC, 0x00000000 },
{ AR5K_PROFCNT_TX, 0x00000000 },
{ AR5K_PROFCNT_RX, 0x00000000 },
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 2942f13c9c4..64fc1eb9b6d 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -24,6 +24,8 @@
* Protocol Control Unit Functions *
\*********************************/
+#include <asm/unaligned.h>
+
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
@@ -44,6 +46,7 @@
*/
int ath5k_hw_set_opmode(struct ath5k_hw *ah)
{
+ struct ath_common *common = ath5k_hw_common(ah);
u32 pcu_reg, beacon_reg, low_id, high_id;
@@ -95,8 +98,8 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
/*
* Set PCU registers
*/
- low_id = AR5K_LOW_ID(ah->ah_sta_id);
- high_id = AR5K_HIGH_ID(ah->ah_sta_id);
+ low_id = get_unaligned_le32(common->macaddr);
+ high_id = get_unaligned_le16(common->macaddr + 4);
ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
@@ -238,28 +241,6 @@ int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
return 0;
}
-
-/****************\
-* BSSID handling *
-\****************/
-
-/**
- * ath5k_hw_get_lladdr - Get station id
- *
- * @ah: The &struct ath5k_hw
- * @mac: The card's mac address
- *
- * Initialize ah->ah_sta_id using the mac address provided
- * (just a memcpy).
- *
- * TODO: Remove it once we merge ath5k_softc and ath5k_hw
- */
-void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
-{
- ATH5K_TRACE(ah->ah_sc);
- memcpy(mac, ah->ah_sta_id, ETH_ALEN);
-}
-
/**
* ath5k_hw_set_lladdr - Set station id
*
@@ -270,17 +251,18 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
*/
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
{
+ struct ath_common *common = ath5k_hw_common(ah);
u32 low_id, high_id;
u32 pcu_reg;
ATH5K_TRACE(ah->ah_sc);
/* Set new station ID */
- memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+ memcpy(common->macaddr, mac, ETH_ALEN);
pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
- low_id = AR5K_LOW_ID(mac);
- high_id = AR5K_HIGH_ID(mac);
+ low_id = get_unaligned_le32(mac);
+ high_id = get_unaligned_le16(mac + 4);
ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
@@ -297,159 +279,51 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
*
* Sets the BSSID which trigers the "SME Join" operation
*/
-void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
+void ath5k_hw_set_associd(struct ath5k_hw *ah)
{
- u32 low_id, high_id;
+ struct ath_common *common = ath5k_hw_common(ah);
u16 tim_offset = 0;
/*
* Set simple BSSID mask on 5212
*/
- if (ah->ah_version == AR5K_AR5212) {
- ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
- AR5K_BSS_IDM0);
- ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
- AR5K_BSS_IDM1);
- }
+ if (ah->ah_version == AR5K_AR5212)
+ ath_hw_setbssidmask(common);
/*
* Set BSSID which triggers the "SME Join" operation
*/
- low_id = AR5K_LOW_ID(bssid);
- high_id = AR5K_HIGH_ID(bssid);
- ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
- ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
- AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
-
- if (assoc_id == 0) {
+ ath5k_hw_reg_write(ah,
+ get_unaligned_le32(common->curbssid),
+ AR5K_BSS_ID0);
+ ath5k_hw_reg_write(ah,
+ get_unaligned_le16(common->curbssid + 4) |
+ ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S),
+ AR5K_BSS_ID1);
+
+ if (common->curaid == 0) {
ath5k_hw_disable_pspoll(ah);
return;
}
AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
- tim_offset ? tim_offset + 4 : 0);
+ tim_offset ? tim_offset + 4 : 0);
ath5k_hw_enable_pspoll(ah, NULL, 0);
}
-/**
- * ath5k_hw_set_bssid_mask - filter out bssids we listen
- *
- * @ah: the &struct ath5k_hw
- * @mask: the bssid_mask, a u8 array of size ETH_ALEN
- *
- * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
- * which bits of the interface's MAC address should be looked at when trying
- * to decide which packets to ACK. In station mode and AP mode with a single
- * BSS every bit matters since we lock to only one BSS. In AP mode with
- * multiple BSSes (virtual interfaces) not every bit matters because hw must
- * accept frames for all BSSes and so we tweak some bits of our mac address
- * in order to have multiple BSSes.
- *
- * NOTE: This is a simple filter and does *not* filter out all
- * relevant frames. Some frames that are not for us might get ACKed from us
- * by PCU because they just match the mask.
- *
- * When handling multiple BSSes you can get the BSSID mask by computing the
- * set of ~ ( MAC XOR BSSID ) for all bssids we handle.
- *
- * When you do this you are essentially computing the common bits of all your
- * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
- * the MAC address to obtain the relevant bits and compare the result with
- * (frame's BSSID & mask) to see if they match.
- */
-/*
- * Simple example: on your card you have have two BSSes you have created with
- * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
- * There is another BSSID-03 but you are not part of it. For simplicity's sake,
- * assuming only 4 bits for a mac address and for BSSIDs you can then have:
- *
- * \
- * MAC: 0001 |
- * BSSID-01: 0100 | --> Belongs to us
- * BSSID-02: 1001 |
- * /
- * -------------------
- * BSSID-03: 0110 | --> External
- * -------------------
- *
- * Our bssid_mask would then be:
- *
- * On loop iteration for BSSID-01:
- * ~(0001 ^ 0100) -> ~(0101)
- * -> 1010
- * bssid_mask = 1010
- *
- * On loop iteration for BSSID-02:
- * bssid_mask &= ~(0001 ^ 1001)
- * bssid_mask = (1010) & ~(0001 ^ 1001)
- * bssid_mask = (1010) & ~(1001)
- * bssid_mask = (1010) & (0110)
- * bssid_mask = 0010
- *
- * A bssid_mask of 0010 means "only pay attention to the second least
- * significant bit". This is because its the only bit common
- * amongst the MAC and all BSSIDs we support. To findout what the real
- * common bit is we can simply "&" the bssid_mask now with any BSSID we have
- * or our MAC address (we assume the hardware uses the MAC address).
- *
- * Now, suppose there's an incoming frame for BSSID-03:
- *
- * IFRAME-01: 0110
- *
- * An easy eye-inspeciton of this already should tell you that this frame
- * will not pass our check. This is beacuse the bssid_mask tells the
- * hardware to only look at the second least significant bit and the
- * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
- * as 1, which does not match 0.
- *
- * So with IFRAME-01 we *assume* the hardware will do:
- *
- * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
- * --> allow = (0010) == 0000 ? 1 : 0;
- * --> allow = 0
- *
- * Lets now test a frame that should work:
- *
- * IFRAME-02: 0001 (we should allow)
- *
- * allow = (0001 & 1010) == 1010
- *
- * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0;
- * --> allow = (0010) == (0010)
- * --> allow = 1
- *
- * Other examples:
- *
- * IFRAME-03: 0100 --> allowed
- * IFRAME-04: 1001 --> allowed
- * IFRAME-05: 1101 --> allowed but its not for us!!!
- *
- */
-int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
{
- u32 low_id, high_id;
+ struct ath_common *common = ath5k_hw_common(ah);
ATH5K_TRACE(ah->ah_sc);
/* Cache bssid mask so that we can restore it
* on reset */
- memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
- if (ah->ah_version == AR5K_AR5212) {
- low_id = AR5K_LOW_ID(mask);
- high_id = AR5K_HIGH_ID(mask);
-
- ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
- ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
-
- return 0;
- }
-
- return -EIO;
+ memcpy(common->bssidmask, mask, ETH_ALEN);
+ if (ah->ah_version == AR5K_AR5212)
+ ath_hw_setbssidmask(common);
}
-
/************\
* RX Control *
\************/
@@ -1157,14 +1031,17 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
/* Invalid entry (key table overflow) */
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
- /* MAC may be NULL if it's a broadcast key. In this case no need to
- * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
+ /*
+ * MAC may be NULL if it's a broadcast key. In this case no need to
+ * to compute get_unaligned_le32 and get_unaligned_le16 as we
+ * already know it.
+ */
if (!mac) {
low_id = 0xffffffff;
high_id = 0xffff | AR5K_KEYTABLE_VALID;
} else {
- low_id = AR5K_LOW_ID(mac);
- high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
+ low_id = get_unaligned_le32(mac);
+ high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID;
}
ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 1a039f2bd73..895990751d3 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1124,77 +1124,148 @@ ath5k_hw_calibration_poll(struct ath5k_hw *ah)
ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
}
+}
+static int sign_extend(int val, const int nbits)
+{
+ int order = BIT(nbits-1);
+ return (val ^ order) - order;
}
-/**
- * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
- *
- * @ah: struct ath5k_hw pointer we are operating on
- * @freq: the channel frequency, just used for error logging
- *
- * This function performs a noise floor calibration of the PHY and waits for
- * it to complete. Then the noise floor value is compared to some maximum
- * noise floor we consider valid.
- *
- * Note that this is different from what the madwifi HAL does: it reads the
- * noise floor and afterwards initiates the calibration. Since the noise floor
- * calibration can take some time to finish, depending on the current channel
- * use, that avoids the occasional timeout warnings we are seeing now.
- *
- * See the following link for an Atheros patent on noise floor calibration:
- * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
- * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
+static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
+{
+ s32 val;
+
+ val = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
+ return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9);
+}
+
+void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
+{
+ int i;
+
+ ah->ah_nfcal_hist.index = 0;
+ for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++)
+ ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
+}
+
+static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
+{
+ struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
+ hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1);
+ hist->nfval[hist->index] = noise_floor;
+}
+
+static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
+{
+ s16 sort[ATH5K_NF_CAL_HIST_MAX];
+ s16 tmp;
+ int i, j;
+
+ memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
+ for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
+ for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
+ if (sort[j] > sort[j-1]) {
+ tmp = sort[j];
+ sort[j] = sort[j-1];
+ sort[j-1] = tmp;
+ }
+ }
+ }
+ for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "cal %d:%d\n", i, sort[i]);
+ }
+ return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2];
+}
+
+/*
+ * When we tell the hardware to perform a noise floor calibration
+ * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically
+ * sample-and-hold the minimum noise level seen at the antennas.
+ * This value is then stored in a ring buffer of recently measured
+ * noise floor values so we have a moving window of the last few
+ * samples.
*
- * XXX: Since during noise floor calibration antennas are detached according to
- * the patent, we should stop tx queues here.
+ * The median of the values in the history is then loaded into the
+ * hardware for its own use for RSSI and CCA measurements.
*/
-int
-ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
{
- int ret;
- unsigned int i;
- s32 noise_floor;
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ u32 val;
+ s16 nf, threshold;
+ u8 ee_mode;
- /*
- * Enable noise floor calibration
- */
- AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_NF);
+ /* keep last value if calibration hasn't completed */
+ if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "NF did not complete in calibration window\n");
- ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_NF, 0, false);
- if (ret) {
- ATH5K_ERR(ah->ah_sc,
- "noise floor calibration timeout (%uMHz)\n", freq);
- return -EAGAIN;
+ return;
}
- /* Wait until the noise floor is calibrated and read the value */
- for (i = 20; i > 0; i--) {
- mdelay(1);
- noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
- noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
- if (noise_floor & AR5K_PHY_NF_ACTIVE) {
- noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
-
- if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
- break;
- }
+ switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
+ case CHANNEL_A:
+ case CHANNEL_T:
+ case CHANNEL_XR:
+ ee_mode = AR5K_EEPROM_MODE_11A;
+ break;
+ case CHANNEL_G:
+ case CHANNEL_TG:
+ ee_mode = AR5K_EEPROM_MODE_11G;
+ break;
+ default:
+ case CHANNEL_B:
+ ee_mode = AR5K_EEPROM_MODE_11B;
+ break;
}
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
- "noise floor %d\n", noise_floor);
- if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
- ATH5K_ERR(ah->ah_sc,
- "noise floor calibration failed (%uMHz)\n", freq);
- return -EAGAIN;
+ /* completed NF calibration, test threshold */
+ nf = ath5k_hw_read_measured_noise_floor(ah);
+ threshold = ee->ee_noise_floor_thr[ee_mode];
+
+ if (nf > threshold) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "noise floor failure detected; "
+ "read %d, threshold %d\n",
+ nf, threshold);
+
+ nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
}
- ah->ah_noise_floor = noise_floor;
+ ath5k_hw_update_nfcal_hist(ah, nf);
+ nf = ath5k_hw_get_median_noise_floor(ah);
- return 0;
+ /* load noise floor (in .5 dBm) so the hardware will use it */
+ val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M;
+ val |= (nf * 2) & AR5K_PHY_NF_M;
+ ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
+
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
+ ~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE));
+
+ ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
+ 0, false);
+
+ /*
+ * Load a high max CCA Power value (-50 dBm in .5 dBm units)
+ * so that we're not capped by the median we just loaded.
+ * This will be used as the initial value for the next noise
+ * floor calibration.
+ */
+ val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M);
+ ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+ AR5K_PHY_AGCCTL_NF_EN |
+ AR5K_PHY_AGCCTL_NF_NOUPDATE |
+ AR5K_PHY_AGCCTL_NF);
+
+ ah->ah_noise_floor = nf;
+
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "noise floor calibrated: %d\n", nf);
}
/*
@@ -1287,7 +1358,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
return ret;
}
- ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+ ath5k_hw_update_noise_floor(ah);
/*
* Re-enable RX/TX and beacons
@@ -1360,7 +1431,7 @@ done:
* since noise floor calibration interrupts rx path while I/Q
* calibration doesn't. We don't need to run noise floor calibration
* as often as I/Q calibration.*/
- ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+ ath5k_hw_update_noise_floor(ah);
/* Initiate a gain_F calibration */
ath5k_hw_request_rfgain_probe(ah);
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index c63ea6afd96..4cb9c5df9f4 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -35,7 +35,7 @@
* released by Atheros and on various debug messages found on the net.
*/
-
+#include "../reg.h"
/*====MAC DMA REGISTERS====*/
@@ -1650,12 +1650,6 @@
#define AR5K_SLEEP2_DTIM_PER_S 16
/*
- * BSSID mask registers
- */
-#define AR5K_BSS_IDM0 0x80e0 /* Upper bits */
-#define AR5K_BSS_IDM1 0x80e4 /* Lower bits */
-
-/*
* TX power control (TPC) register
*
* XXX: PCDAC steps (0.5dbm) or DBM ?
@@ -2039,17 +2033,14 @@
#define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */
/*
- * PHY noise floor status register
+ * PHY noise floor status register (CCA = Clear Channel Assessment)
*/
#define AR5K_PHY_NF 0x9864 /* Register address */
-#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */
-#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */
-#define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M)
-#define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1)
-#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
+#define AR5K_PHY_NF_M 0x000001ff /* Noise floor, written to hardware in 1/2 dBm units */
+#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
#define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */
#define AR5K_PHY_NF_THRESH62_S 12
-#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */
+#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* Minimum measured noise level, read from hardware in 1 dBm units */
#define AR5K_PHY_NF_MINCCA_PWR_S 19
/*
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 34e13c70084..62954fc7786 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -25,6 +25,8 @@
Reset functions and helpers
\*****************************/
+#include <asm/unaligned.h>
+
#include <linux/pci.h> /* To determine if a card is pci-e */
#include <linux/log2.h>
#include "ath5k.h"
@@ -870,6 +872,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool change_channel)
{
+ struct ath_common *common = ath5k_hw_common(ah);
u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo;
u32 phy_tst1;
u8 mode, freq, ee_mode, ant[2];
@@ -1171,10 +1174,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
/* Restore sta_id flags and preserve our mac address*/
- ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id),
- AR5K_STA_ID0);
- ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id),
- AR5K_STA_ID1);
+ ath5k_hw_reg_write(ah,
+ get_unaligned_le32(common->macaddr),
+ AR5K_STA_ID0);
+ ath5k_hw_reg_write(ah,
+ staid1_flags | get_unaligned_le16(common->macaddr + 4),
+ AR5K_STA_ID1);
/*
@@ -1182,8 +1187,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
*/
/* Restore bssid and bssid mask */
- /* XXX: add ah->aid once mac80211 gives this to us */
- ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+ ath5k_hw_set_associd(ah);
/* Set PCU config */
ath5k_hw_set_opmode(ah);
@@ -1289,7 +1293,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* out and/or noise floor calibration might timeout.
*/
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_CAL);
+ AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
/* At the same time start I/Q calibration for QAM constellation
* -no need for CCK- */
@@ -1310,21 +1314,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
channel->center_freq);
}
- /*
- * If we run NF calibration before AGC, it always times out.
- * Binary HAL starts NF and AGC calibration at the same time
- * and only waits for AGC to finish. Also if AGC or NF cal.
- * times out, reset doesn't fail on binary HAL. I believe
- * that's wrong because since rx path is routed to a detector,
- * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
- * enables noise floor calibration after offset calibration and if noise
- * floor calibration fails, reset fails. I believe that's
- * a better approach, we just need to find a polling interval
- * that suits best, even if reset continues we need to make
- * sure that rx path is ready.
- */
- ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-
/* Restore antenna mode */
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index ef5f59c4dd8..99ce066392a 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -1,6 +1,10 @@
+config ATH9K_HW
+ tristate
+
config ATH9K
tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 && WLAN_80211
+ select ATH9K_HW
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
@@ -16,6 +20,8 @@ config ATH9K
If you choose to build a module, it'll be called ath9k.
+if ATH_DEBUG
+
config ATH9K_DEBUG
bool "Atheros ath9k debugging"
depends on ATH9K
@@ -26,3 +32,5 @@ config ATH9K_DEBUG
modprobe ath9k debug=0x00000200
Look in ath9k/debug.h for possible debug masks
+
+endif # ATH_DEBUG
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index ff2c9a26c10..8caf2a8f895 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -1,22 +1,25 @@
-ath9k-y += hw.o \
- eeprom.o \
- eeprom_def.o \
- eeprom_4k.o \
- eeprom_9287.o \
- mac.o \
- calib.o \
- ani.o \
- phy.o \
- beacon.o \
+ath9k-y += beacon.o \
main.o \
recv.o \
xmit.o \
virtual.o \
- rc.o \
- btcoex.o
+ rc.o
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o
obj-$(CONFIG_ATH9K) += ath9k.o
+
+ath9k_hw-y:= hw.o \
+ eeprom.o \
+ eeprom_def.o \
+ eeprom_4k.o \
+ eeprom_9287.o \
+ calib.o \
+ ani.o \
+ phy.o \
+ btcoex.o \
+ mac.o \
+
+obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 2ad7d0280f7..25531f231b6 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -22,27 +22,29 @@
#include "ath9k.h"
/* return bus cachesize in 4B word units */
-static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz)
+static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
{
*csz = L1_CACHE_BYTES >> 2;
}
-static void ath_ahb_cleanup(struct ath_softc *sc)
+static void ath_ahb_cleanup(struct ath_common *common)
{
+ struct ath_softc *sc = (struct ath_softc *)common->priv;
iounmap(sc->mem);
}
-static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
+static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
- struct ath_softc *sc = ah->ah_sc;
+ struct ath_softc *sc = (struct ath_softc *)common->priv;
struct platform_device *pdev = to_platform_device(sc->dev);
struct ath9k_platform_data *pdata;
pdata = (struct ath9k_platform_data *) pdev->dev.platform_data;
if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "%s: flash read failed, offset %08x is out of range\n",
- __func__, off);
+ ath_print(common, ATH_DBG_FATAL,
+ "%s: flash read failed, offset %08x "
+ "is out of range\n",
+ __func__, off);
return false;
}
@@ -116,10 +118,9 @@ static int ath_ahb_probe(struct platform_device *pdev)
sc->hw = hw;
sc->dev = &pdev->dev;
sc->mem = mem;
- sc->bus_ops = &ath_ahb_bus_ops;
sc->irq = irq;
- ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0);
+ ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto err_free_hw;
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 2b493742ef1..2a0cd64c2bf 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
struct ath9k_channel *chan)
@@ -31,8 +31,8 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "No more channel states left. Using channel 0\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANI,
+ "No more channel states left. Using channel 0\n");
return 0;
}
@@ -41,16 +41,17 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah,
enum ath9k_ani_cmd cmd, int param)
{
struct ar5416AniState *aniState = ah->curani;
+ struct ath_common *common = ath9k_hw_common(ah);
switch (cmd & ah->ani_function) {
case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
u32 level = param;
if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
+ ath_print(common, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
return false;
}
@@ -152,10 +153,10 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(firstep)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(firstep));
+ ath_print(common, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned) ARRAY_SIZE(firstep));
return false;
}
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
@@ -174,11 +175,10 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(cycpwrThr1)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned)
- ARRAY_SIZE(cycpwrThr1));
+ ath_print(common, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned) ARRAY_SIZE(cycpwrThr1));
return false;
}
REG_RMW_FIELD(ah, AR_PHY_TIMING5,
@@ -194,25 +194,28 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah,
case ATH9K_ANI_PRESENT:
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "invalid cmd %u\n", cmd);
+ ath_print(common, ATH_DBG_ANI,
+ "invalid cmd %u\n", cmd);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n");
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
- "ofdmWeakSigDetectOff=%d\n",
- aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "cckWeakSigThreshold=%d, "
- "firstepLevel=%d, listenTime=%d\n",
- aniState->cckWeakSigThreshold, aniState->firstepLevel,
- aniState->listenTime);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
+ ath_print(common, ATH_DBG_ANI,
+ "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+ "ofdmWeakSigDetectOff=%d\n",
+ aniState->noiseImmunityLevel,
+ aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff);
+ ath_print(common, ATH_DBG_ANI,
+ "cckWeakSigThreshold=%d, "
+ "firstepLevel=%d, listenTime=%d\n",
+ aniState->cckWeakSigThreshold,
+ aniState->firstepLevel,
+ aniState->listenTime);
+ ath_print(common, ATH_DBG_ANI,
"cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
- aniState->cycleCount, aniState->ofdmPhyErrCount,
+ aniState->cycleCount,
+ aniState->ofdmPhyErrCount,
aniState->cckPhyErrCount);
return true;
@@ -231,6 +234,7 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
static void ath9k_ani_restart(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
if (!DO_ANI(ah))
return;
@@ -240,24 +244,24 @@ static void ath9k_ani_restart(struct ath_hw *ah)
if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
aniState->ofdmPhyErrBase = 0;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "OFDM Trigger is too high for hw counters\n");
+ ath_print(common, ATH_DBG_ANI,
+ "OFDM Trigger is too high for hw counters\n");
} else {
aniState->ofdmPhyErrBase =
AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
}
if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
aniState->cckPhyErrBase = 0;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "CCK Trigger is too high for hw counters\n");
+ ath_print(common, ATH_DBG_ANI,
+ "CCK Trigger is too high for hw counters\n");
} else {
aniState->cckPhyErrBase =
AR_PHY_COUNTMAX - aniState->cckTrigHigh;
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Writing ofdmbase=%u cckbase=%u\n",
- aniState->ofdmPhyErrBase,
- aniState->cckPhyErrBase);
+ ath_print(common, ATH_DBG_ANI,
+ "Writing ofdmbase=%u cckbase=%u\n",
+ aniState->ofdmPhyErrBase,
+ aniState->cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
@@ -271,7 +275,7 @@ static void ath9k_ani_restart(struct ath_hw *ah)
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
struct ar5416AniState *aniState;
int32_t rssi;
@@ -343,7 +347,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
struct ar5416AniState *aniState;
int32_t rssi;
@@ -464,6 +468,7 @@ void ath9k_ani_reset(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
struct ath9k_channel *chan = ah->curchan;
+ struct ath_common *common = ath9k_hw_common(ah);
int index;
if (!DO_ANI(ah))
@@ -475,8 +480,8 @@ void ath9k_ani_reset(struct ath_hw *ah)
if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
&& ah->opmode != NL80211_IFTYPE_ADHOC) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Reset ANI state opmode %u\n", ah->opmode);
+ ath_print(common, ATH_DBG_ANI,
+ "Reset ANI state opmode %u\n", ah->opmode);
ah->stats.ast_ani_reset++;
if (ah->opmode == NL80211_IFTYPE_AP) {
@@ -543,6 +548,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
int32_t listenTime;
u32 phyCnt1, phyCnt2;
u32 ofdmPhyErrCnt, cckPhyErrCnt;
@@ -569,20 +575,22 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
if (phyCnt1 < aniState->ofdmPhyErrBase ||
phyCnt2 < aniState->cckPhyErrBase) {
if (phyCnt1 < aniState->ofdmPhyErrBase) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "phyCnt1 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt1, aniState->ofdmPhyErrBase);
+ ath_print(common, ATH_DBG_ANI,
+ "phyCnt1 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt1,
+ aniState->ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_1,
aniState->ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_MASK_1,
AR_PHY_ERR_OFDM_TIMING);
}
if (phyCnt2 < aniState->cckPhyErrBase) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "phyCnt2 0x%x, resetting "
- "counter value to 0x%x\n",
- phyCnt2, aniState->cckPhyErrBase);
+ ath_print(common, ATH_DBG_ANI,
+ "phyCnt2 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt2,
+ aniState->cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_2,
aniState->cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_MASK_2,
@@ -621,10 +629,13 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
}
}
}
+EXPORT_SYMBOL(ath9k_hw_ani_monitor);
void ath9k_enable_mib_counters(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n");
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -640,7 +651,10 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
/* Freeze the MIB counters, get the stats and then clear them */
void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n");
+
REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
@@ -653,6 +667,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
u32 *rxf_pcnt,
u32 *txf_pcnt)
{
+ struct ath_common *common = ath9k_hw_common(ah);
static u32 cycles, rx_clear, rx_frame, tx_frame;
u32 good = 1;
@@ -662,8 +677,8 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
u32 cc = REG_READ(ah, AR_CCCNT);
if (cycles == 0 || cycles > cc) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "cycle counter wrap. ExtBusy = 0\n");
+ ath_print(common, ATH_DBG_ANI,
+ "cycle counter wrap. ExtBusy = 0\n");
good = 0;
} else {
u32 cc_d = cc - cycles;
@@ -742,6 +757,7 @@ void ath9k_hw_procmibevent(struct ath_hw *ah)
ath9k_ani_restart(ah);
}
}
+EXPORT_SYMBOL(ath9k_hw_procmibevent);
void ath9k_hw_ani_setup(struct ath_hw *ah)
{
@@ -762,9 +778,10 @@ void ath9k_hw_ani_setup(struct ath_hw *ah)
void ath9k_hw_ani_init(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int i;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n");
+ ath_print(common, ATH_DBG_ANI, "Initialize ANI\n");
memset(ah->ani, 0, sizeof(ah->ani));
for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
@@ -786,11 +803,11 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Setting OfdmErrBase = 0x%08x\n",
- ah->ani[0].ofdmPhyErrBase);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
- ah->ani[0].cckPhyErrBase);
+ ath_print(common, ATH_DBG_ANI,
+ "Setting OfdmErrBase = 0x%08x\n",
+ ah->ani[0].ofdmPhyErrBase);
+ ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
+ ah->ani[0].cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
@@ -803,7 +820,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
void ath9k_hw_ani_disable(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
ath9k_hw_disable_mib_counters(ah);
REG_WRITE(ah, AR_PHY_ERR_1, 0);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1d59f10f68d..13dd0202d6b 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -26,7 +26,7 @@
#include "rc.h"
#include "debug.h"
#include "../ath.h"
-#include "btcoex.h"
+#include "../debug.h"
struct ath_node;
@@ -54,15 +54,11 @@ struct ath_node;
#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
-#define ASSERT(exp) BUG_ON(!(exp))
-
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
-static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
struct ath_config {
u32 ath_aggr_prot;
u16 txpowlimit;
@@ -191,7 +187,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
/* minimum h/w qdepth to be sustained to maximize aggregation */
#define ATH_AGGR_MIN_QDEPTH 2
#define ATH_AMPDU_SUBFRAME_DEFAULT 32
-#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
#define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_MAX 4096
@@ -293,7 +288,6 @@ struct ath_tx_control {
#define ATH_RSSI_LPF_LEN 10
#define RSSI_LPF_THRESHOLD -20
-#define ATH9K_RSSI_BAD 0x80
#define ATH_RSSI_EP_MULTIPLIER (1<<7)
#define ATH_EP_MUL(x, mul) ((x) * (mul))
#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
@@ -427,7 +421,6 @@ struct ath_beacon {
void ath_beacon_tasklet(unsigned long data);
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
-int ath_beaconq_setup(struct ath_hw *ah);
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif);
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
@@ -451,6 +444,26 @@ struct ath_ani {
struct timer_list timer;
};
+/* Defines the BT AR_BT_COEX_WGHT used */
+enum ath_stomp_type {
+ ATH_BTCOEX_NO_STOMP,
+ ATH_BTCOEX_STOMP_ALL,
+ ATH_BTCOEX_STOMP_LOW,
+ ATH_BTCOEX_STOMP_NONE
+};
+
+struct ath_btcoex {
+ bool hw_timer_enabled;
+ spinlock_t btcoex_lock;
+ struct timer_list period_timer; /* Timer for BT period */
+ u32 bt_priority_cnt;
+ unsigned long bt_priority_time;
+ int bt_stomp_type; /* Types of BT stomping */
+ u32 btcoex_no_stomp; /* in usec */
+ u32 btcoex_period; /* in usec */
+ struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
+};
+
/********************/
/* LED Control */
/********************/
@@ -484,7 +497,6 @@ struct ath_led {
* Used when PCI device not fully initialized by bootrom/BIOS
*/
#define DEFAULT_CACHELINE 32
-#define ATH_DEFAULT_NOISE_FLOOR -95
#define ATH_REGCLASSIDS_MAX 10
#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
#define ATH_MAX_SW_RETRIES 10
@@ -522,23 +534,14 @@ struct ath_led {
#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
#define SC_OP_BEACON_SYNC BIT(19)
-#define SC_OP_BTCOEX_ENABLED BIT(20)
#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
-struct ath_bus_ops {
- void (*read_cachesize)(struct ath_softc *sc, int *csz);
- void (*cleanup)(struct ath_softc *sc);
- bool (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data);
-};
-
struct ath_wiphy;
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
- struct ath_common common;
-
spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
struct ath_wiphy *pri_wiphy;
struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
@@ -565,24 +568,17 @@ struct ath_softc {
spinlock_t sc_pm_lock;
struct mutex mutex;
- u8 curbssid[ETH_ALEN];
- u8 bssidmask[ETH_ALEN];
u32 intrstatus;
u32 sc_flags; /* SC_OP_* */
u16 curtxpow;
- u16 curaid;
u8 nbcnvifs;
u16 nvifs;
- u8 tx_chainmask;
- u8 rx_chainmask;
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
bool ps_enabled;
unsigned long ps_usecount;
enum ath9k_int imask;
- enum ath9k_ht_extprotspacing ht_extprotspacing;
- enum ath9k_ht_macmode tx_chan_width;
struct ath_config config;
struct ath_rx rx;
@@ -609,10 +605,9 @@ struct ath_softc {
#ifdef CONFIG_ATH9K_DEBUG
struct ath9k_debug debug;
#endif
- struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work;
- struct ath_btcoex_info btcoex_info;
+ struct ath_btcoex btcoex;
};
struct ath_wiphy {
@@ -634,31 +629,22 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);
-static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
-{
- return &ah->ah_sc->common;
-}
-
-static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
+static inline void ath_read_cachesize(struct ath_common *common, int *csz)
{
- return &(ath9k_hw_common(ah)->regulatory);
+ common->bus_ops->read_cachesize(common, csz);
}
-static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
+static inline void ath_bus_cleanup(struct ath_common *common)
{
- sc->bus_ops->read_cachesize(sc, csz);
-}
-
-static inline void ath_bus_cleanup(struct ath_softc *sc)
-{
- sc->bus_ops->cleanup(sc);
+ common->bus_ops->cleanup(common);
}
extern struct ieee80211_ops ath9k_ops;
irqreturn_t ath_isr(int irq, void *dev);
void ath_cleanup(struct ath_softc *sc);
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid);
+int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops);
void ath_detach(struct ath_softc *sc);
const char *ath_mac_bb_name(u32 mac_bb_version);
const char *ath_rf_name(u16 rf_version);
@@ -706,8 +692,5 @@ bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work);
bool ath9k_all_wiphys_idle(struct ath_softc *sc);
-void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
-unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
-
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 45c4ea57616..b10c884f293 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -26,6 +26,7 @@
static int ath_beaconq_config(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
@@ -42,8 +43,8 @@ static int ath_beaconq_config(struct ath_softc *sc)
}
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to update h/w beacon queue parameters\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to update h/w beacon queue parameters\n");
return 0;
} else {
ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
@@ -61,6 +62,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
{
struct sk_buff *skb = bf->bf_mpdu;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_desc *ds;
struct ath9k_11n_rate_series series[4];
const struct ath_rate_table *rt;
@@ -108,7 +110,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
series[0].Tries = 1;
series[0].Rate = rate;
- series[0].ChSel = sc->tx_chainmask;
+ series[0].ChSel = common->tx_chainmask;
series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
series, 4, 0);
@@ -119,6 +121,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_buf *bf;
struct ath_vif *avp;
struct sk_buff *skb;
@@ -172,7 +175,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error on beaconing\n");
return NULL;
}
@@ -192,8 +196,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
if (skb && cabq_depth) {
if (sc->nvifs > 1) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "Flushing previous cabq traffic\n");
+ ath_print(common, ATH_DBG_BEACON,
+ "Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq, false);
}
}
@@ -216,6 +220,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf;
struct ath_vif *avp;
struct sk_buff *skb;
@@ -233,25 +238,14 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
/* NB: caller is known to have already stopped tx dma */
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
ath9k_hw_txstart(ah, sc->beacon.beaconq);
- DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
- sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
-}
-
-int ath_beaconq_setup(struct ath_hw *ah)
-{
- struct ath9k_tx_queue_info qi;
-
- memset(&qi, 0, sizeof(qi));
- qi.tqi_aifs = 1;
- qi.tqi_cwmin = 0;
- qi.tqi_cwmax = 0;
- /* NB: don't enable any interrupts */
- return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
+ ath_print(common, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
+ sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
}
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
{
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp;
struct ath_buf *bf;
struct sk_buff *skb;
@@ -309,7 +303,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
/* NB: the beacon data buffer must be 32-bit aligned. */
skb = ieee80211_beacon_get(sc->hw, vif);
if (skb == NULL) {
- DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n");
+ ath_print(common, ATH_DBG_BEACON, "cannot get skb\n");
return -ENOMEM;
}
@@ -333,9 +327,10 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
- DPRINTF(sc, ATH_DBG_BEACON,
- "stagger beacons, bslot %d intval %u tsfadjust %llu\n",
- avp->av_bslot, intval, (unsigned long long)tsfadjust);
+ ath_print(common, ATH_DBG_BEACON,
+ "stagger beacons, bslot %d intval "
+ "%u tsfadjust %llu\n",
+ avp->av_bslot, intval, (unsigned long long)tsfadjust);
((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
avp->tsf_adjust;
@@ -349,8 +344,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL,
- "dma_mapping_error on beacon alloc\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error on beacon alloc\n");
return -ENOMEM;
}
@@ -386,6 +381,7 @@ void ath_beacon_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf = NULL;
struct ieee80211_vif *vif;
struct ath_wiphy *aphy;
@@ -405,12 +401,12 @@ void ath_beacon_tasklet(unsigned long data)
sc->beacon.bmisscnt++;
if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "missed %u consecutive beacons\n",
- sc->beacon.bmisscnt);
+ ath_print(common, ATH_DBG_BEACON,
+ "missed %u consecutive beacons\n",
+ sc->beacon.bmisscnt);
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "beacon is officially stuck\n");
+ ath_print(common, ATH_DBG_BEACON,
+ "beacon is officially stuck\n");
sc->sc_flags |= SC_OP_TSF_RESET;
ath_reset(sc, false);
}
@@ -419,9 +415,9 @@ void ath_beacon_tasklet(unsigned long data)
}
if (sc->beacon.bmisscnt != 0) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "resume beacon xmit after %u misses\n",
- sc->beacon.bmisscnt);
+ ath_print(common, ATH_DBG_BEACON,
+ "resume beacon xmit after %u misses\n",
+ sc->beacon.bmisscnt);
sc->beacon.bmisscnt = 0;
}
@@ -447,9 +443,9 @@ void ath_beacon_tasklet(unsigned long data)
vif = sc->beacon.bslot[slot];
aphy = sc->beacon.bslot_aphy[slot];
- DPRINTF(sc, ATH_DBG_BEACON,
- "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
- slot, tsf, tsftu, intval, vif);
+ ath_print(common, ATH_DBG_BEACON,
+ "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
+ slot, tsf, tsftu, intval, vif);
bfaddr = 0;
if (vif) {
@@ -490,7 +486,7 @@ void ath_beacon_tasklet(unsigned long data)
* are still pending on the queue.
*/
if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
- DPRINTF(sc, ATH_DBG_FATAL,
+ ath_print(common, ATH_DBG_FATAL,
"beacon queue %u did not stop?\n", sc->beacon.beaconq);
}
@@ -502,6 +498,19 @@ void ath_beacon_tasklet(unsigned long data)
}
}
+static void ath9k_beacon_init(struct ath_softc *sc,
+ u32 next_beacon,
+ u32 beacon_period)
+{
+ if (beacon_period & ATH9K_BEACON_RESET_TSF)
+ ath9k_ps_wakeup(sc);
+
+ ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
+
+ if (beacon_period & ATH9K_BEACON_RESET_TSF)
+ ath9k_ps_restore(sc);
+}
+
/*
* For multi-bss ap support beacons are either staggered evenly over N slots or
* burst together. For the former arrange for the SWBA to be delivered for each
@@ -534,7 +543,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
/* Set the computed AP beacon timers */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
- ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
+ ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
@@ -555,6 +564,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
static void ath_beacon_config_sta(struct ath_softc *sc,
struct ath_beacon_config *conf)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_beacon_state bs;
int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount;
@@ -651,11 +661,11 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
/* TSF out of range threshold fixed at 1 second */
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
- DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
- DPRINTF(sc, ATH_DBG_BEACON,
- "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
- bs.bs_bmissthreshold, bs.bs_sleepduration,
- bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+ ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
+ ath_print(common, ATH_DBG_BEACON,
+ "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
+ bs.bs_bmissthreshold, bs.bs_sleepduration,
+ bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
/* Set the computed STA beacon timers */
@@ -669,6 +679,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
struct ath_beacon_config *conf,
struct ieee80211_vif *vif)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u64 tsf;
u32 tsftu, intval, nexttbtt;
@@ -689,9 +700,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
nexttbtt += intval;
} while (nexttbtt < tsftu);
- DPRINTF(sc, ATH_DBG_BEACON,
- "IBSS nexttbtt %u intval %u (%u)\n",
- nexttbtt, intval, conf->beacon_interval);
+ ath_print(common, ATH_DBG_BEACON,
+ "IBSS nexttbtt %u intval %u (%u)\n",
+ nexttbtt, intval, conf->beacon_interval);
/*
* In IBSS mode enable the beacon timers but only enable SWBA interrupts
@@ -707,7 +718,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
/* Set the computed ADHOC beacon timers */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
- ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
+ ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
@@ -719,6 +730,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
{
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
enum nl80211_iftype iftype;
/* Setup the beacon configuration parameters */
@@ -759,8 +771,8 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
ath_beacon_config_sta(sc, cur_conf);
break;
default:
- DPRINTF(sc, ATH_DBG_CONFIG,
- "Unsupported beaconing mode\n");
+ ath_print(common, ATH_DBG_CONFIG,
+ "Unsupported beaconing mode\n");
return;
}
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 55f607b7699..fb4ac15f3b9 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -14,10 +14,26 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
-static const struct ath_btcoex_config ath_bt_config = { 0, true, true,
- ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true };
+enum ath_bt_mode {
+ ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
+ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
+ ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
+ ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */
+};
+
+struct ath_btcoex_config {
+ u8 bt_time_extend;
+ bool bt_txstate_extend;
+ bool bt_txframe_extend;
+ enum ath_bt_mode bt_mode; /* coexistence mode */
+ bool bt_quiet_collision;
+ bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
+ u8 bt_priority_time;
+ u8 bt_first_slot_time;
+ bool bt_hold_rx_clear;
+};
static const u16 ath_subsysid_tbl[] = {
AR9280_COEX2WIRE_SUBSYSID,
@@ -29,141 +45,38 @@ static const u16 ath_subsysid_tbl[] = {
* Checks the subsystem id of the device to see if it
* supports btcoex
*/
-bool ath_btcoex_supported(u16 subsysid)
+bool ath9k_hw_btcoex_supported(struct ath_hw *ah)
{
int i;
- if (!subsysid)
+ if (!ah->hw_version.subsysid)
return false;
for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++)
- if (subsysid == ath_subsysid_tbl[i])
+ if (ah->hw_version.subsysid == ath_subsysid_tbl[i])
return true;
return false;
}
-/*
- * Detects if there is any priority bt traffic
- */
-static void ath_detect_bt_priority(struct ath_softc *sc)
-{
- struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
- if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio))
- btinfo->bt_priority_cnt++;
-
- if (time_after(jiffies, btinfo->bt_priority_time +
- msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
- if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
- DPRINTF(sc, ATH_DBG_BTCOEX,
- "BT priority traffic detected");
- sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
- } else {
- sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
- }
-
- btinfo->bt_priority_cnt = 0;
- btinfo->bt_priority_time = jiffies;
- }
-}
-
-/*
- * Configures appropriate weight based on stomp type.
- */
-static void ath_btcoex_bt_stomp(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo,
- int stomp_type)
-{
-
- switch (stomp_type) {
- case ATH_BTCOEX_STOMP_ALL:
- ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
- AR_STOMP_ALL_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_LOW:
- ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
- AR_STOMP_LOW_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_NONE:
- ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
- AR_STOMP_NONE_WLAN_WGHT);
- break;
- default:
- DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n");
- break;
- }
-
- ath9k_hw_btcoex_enable(sc->sc_ah);
-}
-
-/*
- * This is the master bt coex timer which runs for every
- * 45ms, bt traffic will be given priority during 55% of this
- * period while wlan gets remaining 45%
- */
-
-static void ath_btcoex_period_timer(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *) data;
- struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
- ath_detect_bt_priority(sc);
-
- spin_lock_bh(&btinfo->btcoex_lock);
-
- ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type);
-
- spin_unlock_bh(&btinfo->btcoex_lock);
-
- if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) {
- if (btinfo->hw_timer_enabled)
- ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
-
- ath_gen_timer_start(sc->sc_ah,
- btinfo->no_stomp_timer,
- (ath9k_hw_gettsf32(sc->sc_ah) +
- btinfo->btcoex_no_stomp),
- btinfo->btcoex_no_stomp * 10);
- btinfo->hw_timer_enabled = true;
- }
-
- mod_timer(&btinfo->period_timer, jiffies +
- msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
-}
-
-/*
- * Generic tsf based hw timer which configures weight
- * registers to time slice between wlan and bt traffic
- */
-
-static void ath_btcoex_no_stomp_timer(void *arg)
-{
- struct ath_softc *sc = (struct ath_softc *)arg;
- struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
- DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n");
-
- spin_lock_bh(&btinfo->btcoex_lock);
-
- if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
- ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE);
- else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
- ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW);
-
- spin_unlock_bh(&btinfo->btcoex_lock);
-}
-
-static int ath_init_btcoex_info(struct ath_hw *hw,
- struct ath_btcoex_info *btcoex_info)
+void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+ const struct ath_btcoex_config ath_bt_config = {
+ .bt_time_extend = 0,
+ .bt_txstate_extend = true,
+ .bt_txframe_extend = true,
+ .bt_mode = ATH_BT_COEX_MODE_SLOTTED,
+ .bt_quiet_collision = true,
+ .bt_rxclear_polarity = true,
+ .bt_priority_time = 2,
+ .bt_first_slot_time = 5,
+ .bt_hold_rx_clear = true,
+ };
u32 i;
- int qnum;
- qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
-
- btcoex_info->bt_coex_mode =
- (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) |
+ btcoex_hw->bt_coex_mode =
+ (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
@@ -174,167 +87,141 @@ static int ath_init_btcoex_info(struct ath_hw *hw,
SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
SM(qnum, AR_BT_QCU_THRESH);
- btcoex_info->bt_coex_mode2 =
+ btcoex_hw->bt_coex_mode2 =
SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
AR_BT_DISABLE_BT_ANT;
- btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+ for (i = 0; i < 32; i++)
+ ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+}
+EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
- btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
+{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
- btcoex_info->btcoex_period / 100;
+ /* connect bt_active to baseband */
+ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
+ AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
- for (i = 0; i < 32; i++)
- hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
- setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer,
- (unsigned long) hw->ah_sc);
+ /* Set input mux for bt_active to gpio pin */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_hw->btactive_gpio);
- btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw,
- ath_btcoex_no_stomp_timer,
- ath_btcoex_no_stomp_timer,
- (void *)hw->ah_sc, AR_FIRST_NDP_TIMER);
+ /* Configure the desired gpio port for input */
+ ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire);
+
+void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
+{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- if (btcoex_info->no_stomp_timer == NULL)
- return -ENOMEM;
+ /* btcoex 3-wire */
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
- spin_lock_init(&btcoex_info->btcoex_lock);
+ /* Set input mux for bt_prority_async and
+ * bt_active_async to GPIO pins */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_hw->btactive_gpio);
- return 0;
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_PRIORITY,
+ btcoex_hw->btpriority_gpio);
+
+ /* Configure the desired GPIO ports for input */
+
+ ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
+ ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio);
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
-int ath9k_hw_btcoex_init(struct ath_hw *ah)
+static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
{
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
- int ret = 0;
-
- if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
- /* connect bt_active to baseband */
- REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
- AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
-
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
-
- /* Set input mux for bt_active to gpio pin */
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_ACTIVE,
- btcoex_info->btactive_gpio);
-
- /* Configure the desired gpio port for input */
- ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
- } else {
- /* btcoex 3-wire */
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
- AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
-
- /* Set input mux for bt_prority_async and
- * bt_active_async to GPIO pins */
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_ACTIVE,
- btcoex_info->btactive_gpio);
-
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_PRIORITY,
- btcoex_info->btpriority_gpio);
-
- /* Configure the desired GPIO ports for input */
-
- ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
- ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio);
-
- ret = ath_init_btcoex_info(ah, btcoex_info);
- }
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- return ret;
+ /* Configure the desired GPIO port for TX_FRAME output */
+ ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
}
-void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
+ u32 bt_weight,
+ u32 wlan_weight)
{
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
-
- if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
- /* Configure the desired GPIO port for TX_FRAME output */
- ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
- } else {
- /*
- * Program coex mode and weight registers to
- * enable coex 3-wire
- */
- REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode);
- REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights);
- REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2);
-
- REG_RMW_FIELD(ah, AR_QUIET1,
- AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
- REG_RMW_FIELD(ah, AR_PCU_MISC,
- AR_PCU_BT_ANT_PREVENT_RX, 0);
-
- ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
- }
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- REG_RMW(ah, AR_GPIO_PDPU,
- (0x2 << (btcoex_info->btactive_gpio * 2)),
- (0x3 << (btcoex_info->btactive_gpio * 2)));
-
- ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED;
+ btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
+ SM(wlan_weight, AR_BTCOEX_WL_WGHT);
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
-void ath9k_hw_btcoex_disable(struct ath_hw *ah)
+static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
{
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0);
+ /*
+ * Program coex mode and weight registers to
+ * enable coex 3-wire
+ */
+ REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
- ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+ REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
- if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) {
- REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
- REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
- REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
- }
-
- ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED;
+ ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
}
-/*
- * Pause btcoex timer and bt duty cycle timer
- */
-void ath_btcoex_timer_pause(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo)
+void ath9k_hw_btcoex_enable(struct ath_hw *ah)
{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- del_timer_sync(&btinfo->period_timer);
+ switch (btcoex_hw->scheme) {
+ case ATH_BTCOEX_CFG_NONE:
+ break;
+ case ATH_BTCOEX_CFG_2WIRE:
+ ath9k_hw_btcoex_enable_2wire(ah);
+ break;
+ case ATH_BTCOEX_CFG_3WIRE:
+ ath9k_hw_btcoex_enable_3wire(ah);
+ break;
+ }
- if (btinfo->hw_timer_enabled)
- ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+ REG_RMW(ah, AR_GPIO_PDPU,
+ (0x2 << (btcoex_hw->btactive_gpio * 2)),
+ (0x3 << (btcoex_hw->btactive_gpio * 2)));
- btinfo->hw_timer_enabled = false;
+ ah->btcoex_hw.enabled = true;
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_enable);
-/*
- * (Re)start btcoex timers
- */
-void ath_btcoex_timer_resume(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo)
+void ath9k_hw_btcoex_disable(struct ath_hw *ah)
{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers");
+ ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
- /* make sure duty cycle timer is also stopped when resuming */
- if (btinfo->hw_timer_enabled)
- ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+ ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- btinfo->bt_priority_cnt = 0;
- btinfo->bt_priority_time = jiffies;
- sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+ if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
+ REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+ }
- mod_timer(&btinfo->period_timer, jiffies);
+ ah->btcoex_hw.enabled = false;
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 297b027fd3c..1ba31a73317 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -17,6 +17,8 @@
#ifndef BTCOEX_H
#define BTCOEX_H
+#include "hw.h"
+
#define ATH_WLANACTIVE_GPIO 5
#define ATH_BTACTIVE_GPIO 6
#define ATH_BTPRIORITY_GPIO 7
@@ -34,67 +36,25 @@ enum ath_btcoex_scheme {
ATH_BTCOEX_CFG_3WIRE,
};
-enum ath_stomp_type {
- ATH_BTCOEX_NO_STOMP,
- ATH_BTCOEX_STOMP_ALL,
- ATH_BTCOEX_STOMP_LOW,
- ATH_BTCOEX_STOMP_NONE
-};
-
-enum ath_bt_mode {
- ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
- ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
- ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
- ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */
-};
-
-struct ath_btcoex_config {
- u8 bt_time_extend;
- bool bt_txstate_extend;
- bool bt_txframe_extend;
- enum ath_bt_mode bt_mode; /* coexistence mode */
- bool bt_quiet_collision;
- bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
- u8 bt_priority_time;
- u8 bt_first_slot_time;
- bool bt_hold_rx_clear;
-};
-
-struct ath_btcoex_info {
- enum ath_btcoex_scheme btcoex_scheme;
+struct ath_btcoex_hw {
+ enum ath_btcoex_scheme scheme;
+ bool enabled;
u8 wlanactive_gpio;
u8 btactive_gpio;
u8 btpriority_gpio;
- u8 bt_duty_cycle; /* BT duty cycle in percentage */
- int bt_stomp_type; /* Types of BT stomping */
u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */
u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */
u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
- u32 btcoex_no_stomp; /* in usec */
- u32 btcoex_period; /* in usec */
- u32 bt_priority_cnt;
- unsigned long bt_priority_time;
- bool hw_timer_enabled;
- spinlock_t btcoex_lock;
- struct timer_list period_timer; /* Timer for BT period */
- struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/
};
-bool ath_btcoex_supported(u16 subsysid);
-int ath9k_hw_btcoex_init(struct ath_hw *ah);
+bool ath9k_hw_btcoex_supported(struct ath_hw *ah);
+void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah);
+void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah);
+void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
+void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
+ u32 bt_weight,
+ u32 wlan_weight);
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
void ath9k_hw_btcoex_disable(struct ath_hw *ah);
-void ath_btcoex_timer_resume(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo);
-void ath_btcoex_timer_pause(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo);
-
-static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info,
- u32 bt_weight,
- u32 wlan_weight)
-{
- btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
- SM(wlan_weight, AR_BTCOEX_WL_WGHT);
-}
#endif
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 0ad6d0b76e9..551f8801459 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
/* We can tune this as we go by monitoring really low values */
#define ATH9K_NF_TOO_LOW -60
@@ -26,11 +26,11 @@
static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
{
if (nf > ATH9K_NF_TOO_LOW) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "noise floor value detected (%d) is "
- "lower than what we think is a "
- "reasonable value (%d)\n",
- nf, ATH9K_NF_TOO_LOW);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "noise floor value detected (%d) is "
+ "lower than what we think is a "
+ "reasonable value (%d)\n",
+ nf, ATH9K_NF_TOO_LOW);
return false;
}
return true;
@@ -89,6 +89,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
static void ath9k_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
+ struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
if (AR_SREV_9280_10_OR_LATER(ah))
@@ -98,8 +99,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 0] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 0] is %d\n", nf);
nfarray[0] = nf;
if (!AR_SREV_9285(ah)) {
@@ -112,8 +113,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 1] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf;
if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
@@ -121,8 +122,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 2] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 2] is %d\n", nf);
nfarray[2] = nf;
}
}
@@ -136,8 +137,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 0] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 0] is %d\n", nf);
nfarray[3] = nf;
if (!AR_SREV_9285(ah)) {
@@ -150,8 +151,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 1] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf;
if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
@@ -159,8 +160,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 2] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 2] is %d\n", nf);
nfarray[5] = nf;
}
}
@@ -188,6 +189,8 @@ static bool getNoiseFloorThresh(struct ath_hw *ah,
static void ath9k_hw_setup_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
currCal->calData->calCountMax);
@@ -195,23 +198,23 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah,
switch (currCal->calData->calType) {
case IQ_MISMATCH_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting IQ Mismatch Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "starting IQ Mismatch Calibration\n");
break;
case ADC_GAIN_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting ADC Gain Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "starting ADC Gain Calibration\n");
break;
case ADC_DC_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting ADC DC Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "starting ADC DC Calibration\n");
break;
case ADC_DC_INIT_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting Init ADC DC Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "starting Init ADC DC Calibration\n");
break;
}
@@ -278,7 +281,7 @@ static bool ath9k_hw_per_calibration(struct ath_hw *ah,
static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
enum ath9k_cal_types calType)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
switch (calType & ah->supp_cals) {
case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
@@ -304,11 +307,11 @@ static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
ah->totalIqCorrMeas[i] +=
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
- ah->cal_samples, i, ah->totalPowerMeasI[i],
- ah->totalPowerMeasQ[i],
- ah->totalIqCorrMeas[i]);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+ ah->cal_samples, i, ah->totalPowerMeasI[i],
+ ah->totalPowerMeasQ[i],
+ ah->totalIqCorrMeas[i]);
}
}
@@ -326,14 +329,14 @@ static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
ah->totalAdcQEvenPhase[i] +=
REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ah->cal_samples, i,
- ah->totalAdcIOddPhase[i],
- ah->totalAdcIEvenPhase[i],
- ah->totalAdcQOddPhase[i],
- ah->totalAdcQEvenPhase[i]);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ah->cal_samples, i,
+ ah->totalAdcIOddPhase[i],
+ ah->totalAdcIEvenPhase[i],
+ ah->totalAdcQOddPhase[i],
+ ah->totalAdcQEvenPhase[i]);
}
}
@@ -351,19 +354,20 @@ static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
ah->totalAdcDcOffsetQEvenPhase[i] +=
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ah->cal_samples, i,
- ah->totalAdcDcOffsetIOddPhase[i],
- ah->totalAdcDcOffsetIEvenPhase[i],
- ah->totalAdcDcOffsetQOddPhase[i],
- ah->totalAdcDcOffsetQEvenPhase[i]);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ah->cal_samples, i,
+ ah->totalAdcDcOffsetIOddPhase[i],
+ ah->totalAdcDcOffsetIEvenPhase[i],
+ ah->totalAdcDcOffsetQOddPhase[i],
+ ah->totalAdcDcOffsetQEvenPhase[i]);
}
}
static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 powerMeasQ, powerMeasI, iqCorrMeas;
u32 qCoffDenom, iCoffDenom;
int32_t qCoff, iCoff;
@@ -374,13 +378,13 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
powerMeasQ = ah->totalPowerMeasQ[i];
iqCorrMeas = ah->totalIqCorrMeas[i];
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting IQ Cal and Correction for Chain %d\n",
- i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Starting IQ Cal and Correction for Chain %d\n",
+ i);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Orignal: Chn %diq_corr_meas = 0x%08x\n",
- i, ah->totalIqCorrMeas[i]);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+ i, ah->totalIqCorrMeas[i]);
iqCorrNeg = 0;
@@ -389,27 +393,28 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
iqCorrNeg = 1;
}
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
- iqCorrNeg);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+ ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+ iqCorrNeg);
iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
qCoffDenom = powerMeasQ / 64;
- if (powerMeasQ != 0) {
+ if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
+ (qCoffDenom != 0)) {
iCoff = iqCorrMeas / iCoffDenom;
qCoff = powerMeasI / qCoffDenom - 64;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d iCoff = 0x%08x\n", i, iCoff);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d qCoff = 0x%08x\n", i, qCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d iCoff = 0x%08x\n", i, iCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d qCoff = 0x%08x\n", i, qCoff);
iCoff = iCoff & 0x3f;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
if (iqCorrNeg == 0x0)
iCoff = 0x40 - iCoff;
@@ -418,9 +423,9 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
else if (qCoff <= -16)
qCoff = 16;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
- i, iCoff, qCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
+ i, iCoff, qCoff);
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
@@ -428,9 +433,9 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
qCoff);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "IQ Cal and Correction done for Chain %d\n",
- i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "IQ Cal and Correction done for Chain %d\n",
+ i);
}
}
@@ -440,6 +445,7 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
u32 qGainMismatch, iGainMismatch, val, i;
@@ -449,21 +455,21 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
qOddMeasOffset = ah->totalAdcQOddPhase[i];
qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting ADC Gain Cal for Chain %d\n", i);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
- iOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = 0x%08x\n", i,
- iEvenMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
- qOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = 0x%08x\n", i,
- qEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Starting ADC Gain Cal for Chain %d\n", i);
+
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+ iOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = 0x%08x\n", i,
+ iEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+ qOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = 0x%08x\n", i,
+ qEvenMeasOffset);
if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
iGainMismatch =
@@ -473,20 +479,20 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
((qOddMeasOffset * 32) /
qEvenMeasOffset) & 0x3f;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_i = 0x%08x\n", i,
- iGainMismatch);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_q = 0x%08x\n", i,
- qGainMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_i = 0x%08x\n", i,
+ iGainMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_q = 0x%08x\n", i,
+ qGainMismatch);
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xfffff000;
val |= (qGainMismatch) | (iGainMismatch << 6);
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "ADC Gain Cal done for Chain %d\n", i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "ADC Gain Cal done for Chain %d\n", i);
}
}
@@ -497,6 +503,7 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 iOddMeasOffset, iEvenMeasOffset, val, i;
int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
const struct ath9k_percal_data *calData =
@@ -510,41 +517,41 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting ADC DC Offset Cal for Chain %d\n", i);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = %d\n", i,
- iOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = %d\n", i,
- iEvenMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = %d\n", i,
- qOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = %d\n", i,
- qEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Starting ADC DC Offset Cal for Chain %d\n", i);
+
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = %d\n", i,
+ iOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = %d\n", i,
+ iEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = %d\n", i,
+ qOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = %d\n", i,
+ qEvenMeasOffset);
iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
numSamples) & 0x1ff;
qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
numSamples) & 0x1ff;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
- iDcMismatch);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
- qDcMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+ iDcMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+ qDcMismatch);
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xc0000fff;
val |= (qDcMismatch << 12) | (iDcMismatch << 21);
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "ADC DC Offset Cal done for Chain %d\n", i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "ADC DC Offset Cal done for Chain %d\n", i);
}
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
@@ -555,7 +562,8 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
/* This is done for the currently configured channel */
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
struct ath9k_cal_list *currCal = ah->cal_list_curr;
if (!ah->curchan)
@@ -568,24 +576,25 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
return true;
if (currCal->calState != CAL_DONE) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Calibration state incorrect, %d\n",
- currCal->calState);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Calibration state incorrect, %d\n",
+ currCal->calState);
return true;
}
if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
return true;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Resetting Cal %d state for channel %u\n",
- currCal->calData->calType, conf->channel->center_freq);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Resetting Cal %d state for channel %u\n",
+ currCal->calData->calType, conf->channel->center_freq);
ah->curchan->CalValid &= ~currCal->calData->calType;
currCal->calState = CAL_WAITING;
return false;
}
+EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
void ath9k_hw_start_nfcal(struct ath_hw *ah)
{
@@ -645,11 +654,11 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
- for (j = 0; j < 1000; j++) {
+ for (j = 0; j < 5; j++) {
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_NF) == 0)
break;
- udelay(10);
+ udelay(50);
}
for (i = 0; i < NUM_NF_READINGS; i++) {
@@ -665,6 +674,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
int16_t ath9k_hw_getnf(struct ath_hw *ah,
struct ath9k_channel *chan)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int16_t nf, nfThresh;
int16_t nfarray[NUM_NF_READINGS] = { 0 };
struct ath9k_nfcal_hist *h;
@@ -672,8 +682,8 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
chan->channelFlags &= (~CHANNEL_CW_INT);
if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF did not complete in calibration window\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF did not complete in calibration window\n");
nf = 0;
chan->rawNoiseFloor = nf;
return chan->rawNoiseFloor;
@@ -682,10 +692,10 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
nf = nfarray[0];
if (getNoiseFloorThresh(ah, c->band, &nfThresh)
&& nf > nfThresh) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "noise floor failed detected; "
- "detected %d, threshold %d\n",
- nf, nfThresh);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "noise floor failed detected; "
+ "detected %d, threshold %d\n",
+ nf, nfThresh);
chan->channelFlags |= CHANNEL_CW_INT;
}
}
@@ -737,51 +747,73 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
return nf;
}
+EXPORT_SYMBOL(ath9k_hw_getchan_noise);
-static void ath9k_olc_temp_compensation(struct ath_hw *ah)
+static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah)
{
- u32 rddata, i;
- int delta, currPDADC, regval, slope;
+ u32 rddata;
+ int32_t delta, currPDADC, slope;
rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+ if (ah->initPDADC == 0 || currPDADC == 0) {
+ /*
+ * Zero value indicates that no frames have been transmitted yet,
+ * can't do temperature compensation until frames are transmitted.
+ */
+ return;
+ } else {
+ slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
+
+ if (slope == 0) { /* to avoid divide by zero case */
+ delta = 0;
+ } else {
+ delta = ((currPDADC - ah->initPDADC)*4) / slope;
+ }
+ REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
+ AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+ REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
+ AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+ }
+}
+
+static void ath9k_olc_temp_compensation(struct ath_hw *ah)
+{
+ u32 rddata, i;
+ int delta, currPDADC, regval;
if (OLC_FOR_AR9287_10_LATER) {
+ ath9k_olc_temp_compensation_9287(ah);
+ } else {
+ rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
+ currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+
if (ah->initPDADC == 0 || currPDADC == 0) {
return;
} else {
- slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
- if (slope == 0)
- delta = 0;
+ if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
+ delta = (currPDADC - ah->initPDADC + 4) / 8;
else
- delta = ((currPDADC - ah->initPDADC)*4) / slope;
- REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
- AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
- REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
- AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
- }
- } else {
- if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
- delta = (currPDADC - ah->initPDADC + 4) / 8;
- else
- delta = (currPDADC - ah->initPDADC + 5) / 10;
-
- if (delta != ah->PDADCdelta) {
- ah->PDADCdelta = delta;
- for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
- regval = ah->originalGain[i] - delta;
- if (regval < 0)
- regval = 0;
-
- REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4,
- AR_PHY_TX_GAIN, regval);
+ delta = (currPDADC - ah->initPDADC + 5) / 10;
+
+ if (delta != ah->PDADCdelta) {
+ ah->PDADCdelta = delta;
+ for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
+ regval = ah->originalGain[i] - delta;
+ if (regval < 0)
+ regval = 0;
+
+ REG_RMW_FIELD(ah,
+ AR_PHY_TX_GAIN_TBL1 + i * 4,
+ AR_PHY_TX_GAIN, regval);
+ }
}
}
}
}
-static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
+static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset)
{
u32 regVal;
unsigned int i;
@@ -857,10 +889,19 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
REG_WRITE(ah, 0x7834, regVal);
}
- /* Empirical offset correction */
-#if 0
- REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20);
-#endif
+ regVal = (regVal >>20) & 0x7f;
+
+ /* Update PA cal info */
+ if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
+ if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+ ah->pacal_info.max_skipcount =
+ 2 * ah->pacal_info.max_skipcount;
+ ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+ } else {
+ ah->pacal_info.max_skipcount = 1;
+ ah->pacal_info.skipcount = 0;
+ ah->pacal_info.prev_offset = regVal;
+ }
regVal = REG_READ(ah, 0x7834);
regVal |= 0x1;
@@ -875,7 +916,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
{
-
+ struct ath_common *common = ath9k_hw_common(ah);
u32 regVal;
int i, offset, offs_6_1, offs_0;
u32 ccomp_org, reg_field;
@@ -889,7 +930,7 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
{ 0x7838, 0 },
};
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
/* PA CAL is not needed for high power solution */
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
@@ -1011,7 +1052,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
if (longcal) {
/* Do periodic PAOffset Cal */
if (AR_SREV_9271(ah))
- ath9k_hw_9271_pa_cal(ah);
+ ath9k_hw_9271_pa_cal(ah, false);
else if (AR_SREV_9285_11_OR_LATER(ah)) {
if (!ah->pacal_info.skipcount)
ath9k_hw_9285_pa_cal(ah, false);
@@ -1036,9 +1077,13 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
return iscaldone;
}
+EXPORT_SYMBOL(ath9k_hw_calibrate);
+/* Carrier leakage Calibration fix */
static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
if (IS_CHAN_HT20(chan)) {
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
@@ -1049,9 +1094,9 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset "
- "calibration failed to complete in "
- "1ms; noisy ??\n");
+ ath_print(common, ATH_DBG_CALIBRATE, "offset "
+ "calibration failed to complete in "
+ "1ms; noisy ??\n");
return false;
}
REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
@@ -1064,8 +1109,8 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration "
- "failed to complete in 1ms; noisy ??\n");
+ ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
+ "failed to complete in 1ms; noisy ??\n");
return false;
}
@@ -1078,7 +1123,9 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
{
- if (AR_SREV_9285_12_OR_LATER(ah)) {
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
if (!ar9285_clc(ah, chan))
return false;
} else {
@@ -1098,9 +1145,9 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
/* Poll for offset calibration complete */
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "offset calibration failed to complete in 1ms; "
- "noisy environment?\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "offset calibration failed to "
+ "complete in 1ms; noisy environment?\n");
return false;
}
@@ -1114,7 +1161,9 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
}
/* Do PA Calibration */
- if (AR_SREV_9285_11_OR_LATER(ah))
+ if (AR_SREV_9271(ah))
+ ath9k_hw_9271_pa_cal(ah, true);
+ else if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah, true);
/* Do NF Calibration after DC offset and other calibrations */
@@ -1128,20 +1177,20 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
INIT_CAL(&ah->adcgain_caldata);
INSERT_CAL(ah, &ah->adcgain_caldata);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling ADC Gain Calibration.\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "enabling ADC Gain Calibration.\n");
}
if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
INIT_CAL(&ah->adcdc_caldata);
INSERT_CAL(ah, &ah->adcdc_caldata);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling ADC DC Calibration.\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "enabling ADC DC Calibration.\n");
}
if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling IQ Calibration.\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "enabling IQ Calibration.\n");
}
ah->cal_list_curr = ah->cal_list;
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 9028ab193e4..b2c873e9748 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -17,6 +17,8 @@
#ifndef CALIB_H
#define CALIB_H
+#include "hw.h"
+
extern const struct ath9k_percal_data iq_cal_multi_sample;
extern const struct ath9k_percal_data iq_cal_single_sample;
extern const struct ath9k_percal_data adc_gain_cal_multi_sample;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 2be4c225204..84f44269de4 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -18,26 +18,13 @@
#include "ath9k.h"
-static unsigned int ath9k_debug = DBG_DEFAULT;
-module_param_named(debug, ath9k_debug, uint, 0);
+#define REG_WRITE_D(_ah, _reg, _val) \
+ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
+#define REG_READ_D(_ah, _reg) \
+ ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
static struct dentry *ath9k_debugfs_root;
-void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...)
-{
- if (!sc)
- return;
-
- if (sc->debug.debug_mask & dbg_mask) {
- va_list args;
-
- va_start(args, fmt);
- printk(KERN_DEBUG "ath9k: ");
- vprintk(fmt, args);
- va_end(args);
- }
-}
-
static int ath9k_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -48,10 +35,11 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask);
+ len = snprintf(buf, sizeof(buf), "0x%08x\n", common->debug_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -59,6 +47,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long mask;
char buf[32];
ssize_t len;
@@ -71,7 +60,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
if (strict_strtoul(buf, 0, &mask))
return -EINVAL;
- sc->debug.debug_mask = mask;
+ common->debug_mask = mask;
return count;
}
@@ -95,7 +84,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
ath9k_ps_wakeup(sc);
- REG_WRITE(ah, AR_MACMISC,
+ REG_WRITE_D(ah, AR_MACMISC,
((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
(AR_MACMISC_MISC_OBS_BUS_1 <<
AR_MACMISC_MISC_OBS_BUS_MSB_S)));
@@ -107,7 +96,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
if (i % 4 == 0)
len += snprintf(buf + len, sizeof(buf) - len, "\n");
- val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
+ val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32)));
len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ",
i, val[i]);
}
@@ -157,9 +146,9 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n",
- REG_READ(ah, AR_OBS_BUS_1));
+ REG_READ_D(ah, AR_OBS_BUS_1));
len += snprintf(buf + len, sizeof(buf) - len,
- "AR_CR: 0x%x \n", REG_READ(ah, AR_CR));
+ "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR));
ath9k_ps_restore(sc);
@@ -376,12 +365,12 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
aphy->chan_idx, aphy->chan_is_ht);
}
- put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr);
- put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
+ put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
+ put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addr: %pM\n", addr);
- put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr);
- put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
+ put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
+ put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
@@ -568,9 +557,10 @@ static const struct file_operations fops_xmit = {
.owner = THIS_MODULE
};
-int ath9k_init_debug(struct ath_softc *sc)
+int ath9k_init_debug(struct ath_hw *ah)
{
- sc->debug.debug_mask = ath9k_debug;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
if (!ath9k_debugfs_root)
return -ENOENT;
@@ -619,12 +609,15 @@ int ath9k_init_debug(struct ath_softc *sc)
return 0;
err:
- ath9k_exit_debug(sc);
+ ath9k_exit_debug(ah);
return -ENOMEM;
}
-void ath9k_exit_debug(struct ath_softc *sc)
+void ath9k_exit_debug(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
debugfs_remove(sc->debug.debugfs_xmit);
debugfs_remove(sc->debug.debugfs_wiphy);
debugfs_remove(sc->debug.debugfs_rcstat);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 7241f474833..749e85d5755 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -17,25 +17,7 @@
#ifndef DEBUG_H
#define DEBUG_H
-enum ATH_DEBUG {
- ATH_DBG_RESET = 0x00000001,
- ATH_DBG_QUEUE = 0x00000002,
- ATH_DBG_EEPROM = 0x00000004,
- ATH_DBG_CALIBRATE = 0x00000008,
- ATH_DBG_INTERRUPT = 0x00000010,
- ATH_DBG_REGULATORY = 0x00000020,
- ATH_DBG_ANI = 0x00000040,
- ATH_DBG_XMIT = 0x00000080,
- ATH_DBG_BEACON = 0x00000100,
- ATH_DBG_CONFIG = 0x00000200,
- ATH_DBG_FATAL = 0x00000400,
- ATH_DBG_PS = 0x00000800,
- ATH_DBG_HWTIMER = 0x00001000,
- ATH_DBG_BTCOEX = 0x00002000,
- ATH_DBG_ANY = 0xffffffff
-};
-
-#define DBG_DEFAULT (ATH_DBG_FATAL)
+#include "hw.h"
struct ath_txq;
struct ath_buf;
@@ -140,7 +122,6 @@ struct ath_stats {
};
struct ath9k_debug {
- int debug_mask;
struct dentry *debugfs_phy;
struct dentry *debugfs_debug;
struct dentry *debugfs_dma;
@@ -151,9 +132,9 @@ struct ath9k_debug {
struct ath_stats stats;
};
-void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
-int ath9k_init_debug(struct ath_softc *sc);
-void ath9k_exit_debug(struct ath_softc *sc);
+int ath9k_init_debug(struct ath_hw *ah);
+void ath9k_exit_debug(struct ath_hw *ah);
+
int ath9k_debug_create_root(void);
void ath9k_debug_remove_root(void);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
@@ -165,17 +146,12 @@ void ath_debug_stat_retries(struct ath_softc *sc, int rix,
#else
-static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
- const char *fmt, ...)
-{
-}
-
-static inline int ath9k_init_debug(struct ath_softc *sc)
+static inline int ath9k_init_debug(struct ath_hw *ah)
{
return 0;
}
-static inline void ath9k_exit_debug(struct ath_softc *sc)
+static inline void ath9k_exit_debug(struct ath_hw *ah)
{
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index b6e52d0f8c4..dacaae93414 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
{
@@ -83,11 +83,9 @@ bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
return false;
}
-bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
+bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
{
- struct ath_softc *sc = ah->ah_sc;
-
- return sc->bus_ops->eeprom_read(ah, off, data);
+ return common->bus_ops->eeprom_read(common, off, data);
}
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 4fe33f7eee9..2f2993b50e2 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -17,6 +17,7 @@
#ifndef EEPROM_H
#define EEPROM_H
+#include "../ath.h"
#include <net/cfg80211.h>
#define AH_USE_EEPROM 0x1
@@ -133,6 +134,7 @@
#define AR5416_EEP_MINOR_VER_17 0x11
#define AR5416_EEP_MINOR_VER_19 0x13
#define AR5416_EEP_MINOR_VER_20 0x14
+#define AR5416_EEP_MINOR_VER_21 0x15
#define AR5416_EEP_MINOR_VER_22 0x16
#define AR5416_NUM_5G_CAL_PIERS 8
@@ -153,7 +155,7 @@
#define AR5416_BCHAN_UNUSED 0xFF
#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
#define AR5416_MAX_CHAINS 3
-#define AR5416_PWR_TABLE_OFFSET -5
+#define AR5416_PWR_TABLE_OFFSET_DB -5
/* Rx gain type values */
#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0
@@ -301,7 +303,7 @@ struct base_eep_header {
u8 txGainType;
u8 rcChainMask;
u8 desiredScaleCCK;
- u8 power_table_offset;
+ u8 pwr_table_offset;
u8 frac_n_5g;
u8 futureBase_3[21];
} __packed;
@@ -638,6 +640,7 @@ struct ar9287_eeprom {
} __packed;
enum reg_ext_bitmap {
+ REG_EXT_FCC_MIDBAND = 0,
REG_EXT_JAPAN_MIDBAND = 1,
REG_EXT_FCC_DFS_HT40 = 2,
REG_EXT_JAPAN_NONDFS_HT40 = 3,
@@ -684,7 +687,7 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
int16_t targetRight);
bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
u16 *indexL, u16 *indexR);
-bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data);
+bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data);
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
u8 *pVpdList, u16 numIntercepts,
u8 *pRetVpdList);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index b8eca7be5f3..58167d861dc 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
{
@@ -29,20 +29,21 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
{
#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eep_data = (u16 *)&ah->eeprom.map4k;
int addr, eep_start_loc = 0;
eep_start_loc = 64;
if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Reading from EEPROM, not flash\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
}
for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Unable to read eeprom region \n");
+ if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
+ ath_print(common, ATH_DBG_EEPROM,
+ "Unable to read eeprom region \n");
return false;
}
eep_data++;
@@ -55,6 +56,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
{
#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_4k *eep =
(struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
u16 *eepdata, temp, magic, magic2;
@@ -64,15 +66,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
&magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Reading Magic # failed\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Reading Magic # failed\n");
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_print(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -87,16 +89,16 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "endianness mismatch.\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
return -EINVAL;
}
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map4k.baseEepHeader.length);
@@ -117,8 +119,8 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
u32 integer;
u16 word;
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing\n");
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -160,9 +162,9 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ ath_print(common, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -208,6 +210,8 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
return pBase->rxMask;
case EEP_FRAC_N_5G:
return 0;
+ case EEP_PWR_TABLE_OFFSET:
+ return AR5416_PWR_TABLE_OFFSET_DB;
default:
return 0;
}
@@ -385,6 +389,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
struct cal_data_per_freq_4k *pRawDataset;
u8 *pCalBChans = NULL;
@@ -470,21 +475,21 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -750,7 +755,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
if (AR_SREV_9280_10_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
}
/* OFDM power per rate */
@@ -1148,20 +1153,21 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
{
#define EEP_MAP4K_SPURCHAN \
(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
+ struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP4K_SPURCHAN;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index c20c21a79b2..839d05a1df2 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
{
@@ -29,20 +29,22 @@ static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eep_data;
int addr, eep_start_loc = AR9287_EEP_START_LOC;
eep_data = (u16 *)eep;
if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Reading from EEPROM, not flash\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
}
for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Unable to read eeprom region \n");
+ if (!ath9k_hw_nvram_read(common,
+ addr + eep_start_loc, eep_data)) {
+ ath_print(common, ATH_DBG_EEPROM,
+ "Unable to read eeprom region \n");
return false;
}
eep_data++;
@@ -57,17 +59,18 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
int i, addr;
bool need_swap = false;
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct ath_common *common = ath9k_hw_common(ah);
if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read
- (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Reading Magic # failed\n");
+ if (!ath9k_hw_nvram_read(common,
+ AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Reading Magic # failed\n");
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_print(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -83,15 +86,15 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "endianness mismatch.\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
return -EINVAL;
}
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
- "True" : "False");
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
+ "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map9287.baseEepHeader.length);
@@ -148,9 +151,9 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
|| ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ ath_print(common, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -436,6 +439,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct cal_data_per_freq_ar9287 *pRawDataset;
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
u8 *pCalBChans = NULL;
@@ -564,24 +568,25 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
& 0xFF) << 24) ;
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1,
- pdadcValues[4 * j + 1],
- 4 * j + 2,
- pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x "
+ "%8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1,
+ pdadcValues[4 * j + 1],
+ 4 * j + 2,
+ pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -831,6 +836,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
{
#define INCREASE_MAXPOW_BY_TWO_CHAIN 6
#define INCREASE_MAXPOW_BY_THREE_CHAIN 10
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
@@ -966,8 +972,8 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
INCREASE_MAXPOW_BY_THREE_CHAIN;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
break;
}
}
@@ -1138,19 +1144,20 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
{
#define EEP_MAP9287_SPURCHAN \
(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+ struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP9287_SPURCHAN;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 4071fc91da0..404a0341242 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static void ath9k_get_txgain_index(struct ath_hw *ah,
struct ath9k_channel *chan,
@@ -89,14 +89,15 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
{
#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eep_data = (u16 *)&ah->eeprom.def;
int addr, ar5416_eep_start_loc = 0x100;
for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+ if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc,
eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Unable to read eeprom region\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Unable to read eeprom region\n");
return false;
}
eep_data++;
@@ -109,19 +110,20 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
{
struct ar5416_eeprom_def *eep =
(struct ar5416_eeprom_def *) &ah->eeprom.def;
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eepdata, temp, magic, magic2;
u32 sum = 0, el;
bool need_swap = false;
int i, addr, size;
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n");
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n");
return false;
}
if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_print(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -137,16 +139,16 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "Endianness mismatch.\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "Endianness mismatch.\n");
return -EINVAL;
}
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.def.baseEepHeader.length);
@@ -167,8 +169,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
u32 integer, j;
u16 word;
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing.\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing.\n");
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -214,8 +216,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ ath_print(common, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -289,6 +291,11 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
return pBase->frac_n_5g;
else
return 0;
+ case EEP_PWR_TABLE_OFFSET:
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_21)
+ return pBase->pwr_table_offset;
+ else
+ return AR5416_PWR_TABLE_OFFSET_DB;
default:
return 0;
}
@@ -739,6 +746,76 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
return;
}
+static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah,
+ u16 *gb,
+ u16 numXpdGain,
+ u16 pdGainOverlap_t2,
+ int8_t pwr_table_offset,
+ int16_t *diff)
+
+{
+ u16 k;
+
+ /* Prior to writing the boundaries or the pdadc vs. power table
+ * into the chip registers the default starting point on the pdadc
+ * vs. power table needs to be checked and the curve boundaries
+ * adjusted accordingly
+ */
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ u16 gb_limit;
+
+ if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
+ /* get the difference in dB */
+ *diff = (u16)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB);
+ /* get the number of half dB steps */
+ *diff *= 2;
+ /* change the original gain boundary settings
+ * by the number of half dB steps
+ */
+ for (k = 0; k < numXpdGain; k++)
+ gb[k] = (u16)(gb[k] - *diff);
+ }
+ /* Because of a hardware limitation, ensure the gain boundary
+ * is not larger than (63 - overlap)
+ */
+ gb_limit = (u16)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2);
+
+ for (k = 0; k < numXpdGain; k++)
+ gb[k] = (u16)min(gb_limit, gb[k]);
+ }
+
+ return *diff;
+}
+
+static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
+ int8_t pwr_table_offset,
+ int16_t diff,
+ u8 *pdadcValues)
+{
+#define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff)
+ u16 k;
+
+ /* If this is a board that has a pwrTableOffset that differs from
+ * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
+ * pdadc vs pwr table needs to be adjusted prior to writing to the
+ * chip.
+ */
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
+ /* shift the table to start at the new offset */
+ for (k = 0; k < (u16)NUM_PDADC(diff); k++ ) {
+ pdadcValues[k] = pdadcValues[k + diff];
+ }
+
+ /* fill the back of the table */
+ for (k = (u16)NUM_PDADC(diff); k < NUM_PDADC(0); k++) {
+ pdadcValues[k] = pdadcValues[NUM_PDADC(diff)];
+ }
+ }
+ }
+#undef NUM_PDADC
+}
+
static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
@@ -746,7 +823,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
#define SM_PDGAIN_B(x, y) \
SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y)
-
+ struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
struct cal_data_per_freq *pRawDataset;
u8 *pCalBChans = NULL;
@@ -754,15 +831,18 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
u16 numPiers, i, j;
- int16_t tMinCalPower;
+ int16_t tMinCalPower, diff = 0;
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
u32 reg32, regOffset, regChainOffset;
int16_t modalIdx;
+ int8_t pwr_table_offset;
modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+ pwr_table_offset = ah->eep_ops->get_eeprom(ah, EEP_PWR_TABLE_OFFSET);
+
if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
AR5416_EEP_MINOR_VER_2) {
pdGainOverlap_t2 =
@@ -842,6 +922,13 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
numXpdGain);
}
+ diff = ath9k_change_gain_boundary_setting(ah,
+ gainBoundaries,
+ numXpdGain,
+ pdGainOverlap_t2,
+ pwr_table_offset,
+ &diff);
+
if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
if (OLC_FOR_AR9280_20_LATER) {
REG_WRITE(ah,
@@ -862,6 +949,10 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
}
}
+
+ ath9k_adjust_pdadc_values(ah, pwr_table_offset,
+ diff, pdadcValues);
+
regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
for (j = 0; j < 32; j++) {
reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
@@ -870,20 +961,20 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | PDADC %3d "
- "Value %3d | PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | PDADC %3d "
- "Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | PDADC %3d "
+ "Value %3d | PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | PDADC %3d "
+ "Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -1197,8 +1288,13 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
}
if (AR_SREV_9280_10_OR_LATER(ah)) {
- for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ for (i = 0; i < Ar5416RateSize; i++) {
+ int8_t pwr_table_offset;
+
+ pwr_table_offset = ah->eep_ops->get_eeprom(ah,
+ EEP_PWR_TABLE_OFFSET);
+ ratesArray[i] -= pwr_table_offset * 2;
+ }
}
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
@@ -1297,7 +1393,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
if (AR_SREV_9280_10_OR_LATER(ah))
regulatory->max_power_level =
- ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+ ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2;
else
regulatory->max_power_level = ratesArray[i];
@@ -1311,8 +1407,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
break;
}
}
@@ -1349,20 +1445,21 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
{
#define EEP_DEF_SPURCHAN \
(ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
+ struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_DEF_SPURCHAN;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index ca7694caf36..cab17c6c8a3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -16,9 +16,9 @@
#include <linux/io.h>
#include <asm/unaligned.h>
-#include <linux/pci.h>
-#include "ath9k.h"
+#include "hw.h"
+#include "rc.h"
#include "initvals.h"
#define ATH9K_CLOCK_RATE_CCK 22
@@ -26,21 +26,37 @@
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
-static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode);
+static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan);
static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
struct ar5416_eeprom_def *pEepData,
u32 reg, u32 value);
static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
+MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static int __init ath9k_init(void)
+{
+ return 0;
+}
+module_init(ath9k_init);
+
+static void __exit ath9k_exit(void)
+{
+ return;
+}
+module_exit(ath9k_exit);
+
/********************/
/* Helper Functions */
/********************/
static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (!ah->curchan) /* should really check for CCK instead */
return clks / ATH9K_CLOCK_RATE_CCK;
@@ -52,7 +68,7 @@ static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (conf_is_ht40(conf))
return ath9k_hw_mac_usec(ah, clks) / 2;
@@ -62,7 +78,7 @@ static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (!ah->curchan) /* should really check for CCK instead */
return usecs *ATH9K_CLOCK_RATE_CCK;
@@ -73,7 +89,7 @@ static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (conf_is_ht40(conf))
return ath9k_hw_mac_clks(ah, usecs) * 2;
@@ -81,38 +97,6 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
return ath9k_hw_mac_clks(ah, usecs);
}
-/*
- * Read and write, they both share the same lock. We do this to serialize
- * reads and writes on Atheros 802.11n PCI devices only. This is required
- * as the FIFO on these devices can only accept sanely 2 requests. After
- * that the device goes bananas. Serializing the reads/writes prevents this
- * from happening.
- */
-
-void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val)
-{
- if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
- unsigned long flags;
- spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
- iowrite32(val, ah->ah_sc->mem + reg_offset);
- spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
- } else
- iowrite32(val, ah->ah_sc->mem + reg_offset);
-}
-
-unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset)
-{
- u32 val;
- if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
- unsigned long flags;
- spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
- val = ioread32(ah->ah_sc->mem + reg_offset);
- spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
- } else
- val = ioread32(ah->ah_sc->mem + reg_offset);
- return val;
-}
-
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
{
int i;
@@ -126,12 +110,13 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
udelay(AH_TIME_QUANTUM);
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
- timeout, reg, REG_READ(ah, reg), mask, val);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANY,
+ "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+ timeout, reg, REG_READ(ah, reg), mask, val);
return false;
}
+EXPORT_SYMBOL(ath9k_hw_wait);
u32 ath9k_hw_reverse_bits(u32 val, u32 n)
{
@@ -210,15 +195,16 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
}
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Unknown phy %u (rate ix %u)\n",
- rates->info[rateix].phy, rateix);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Unknown phy %u (rate ix %u)\n",
+ rates->info[rateix].phy, rateix);
txTime = 0;
break;
}
return txTime;
}
+EXPORT_SYMBOL(ath9k_hw_computetxtime);
void ath9k_hw_get_channel_centers(struct ath_hw *ah,
struct ath9k_channel *chan,
@@ -245,10 +231,9 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,
centers->ctl_center =
centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
+ /* 25 MHz spacing is supported by hw but not on upper layers */
centers->ext_center =
- centers->synth_center + (extoff *
- ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
- HT40_CHANNEL_CENTER_SHIFT : 15));
+ centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
}
/******************/
@@ -317,6 +302,7 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
static bool ath9k_hw_chip_test(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
u32 regHold[2];
u32 patternData[4] = { 0x55555555,
@@ -335,10 +321,11 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (rdData != wrData) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "address test failed "
- "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
- addr, wrData, rdData);
+ ath_print(common, ATH_DBG_FATAL,
+ "address test failed "
+ "addr: 0x%08x - wr:0x%08x != "
+ "rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -347,10 +334,11 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (wrData != rdData) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "address test failed "
- "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
- addr, wrData, rdData);
+ ath_print(common, ATH_DBG_FATAL,
+ "address test failed "
+ "addr: 0x%08x - wr:0x%08x != "
+ "rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -433,6 +421,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
if (num_possible_cpus() > 1)
ah->config.serialize_regmode = SER_REG_MODE_AUTO;
}
+EXPORT_SYMBOL(ath9k_hw_init);
static void ath9k_hw_init_defaults(struct ath_hw *ah)
{
@@ -472,8 +461,8 @@ static int ath9k_hw_rfattach(struct ath_hw *ah)
rfStatus = ath9k_hw_init_rf(ah, &ecode);
if (!rfStatus) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "RF setup failed, status: %u\n", ecode);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "RF setup failed, status: %u\n", ecode);
return ecode;
}
@@ -497,9 +486,9 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah)
case AR_RAD2122_SREV_MAJOR:
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Radio Chip Rev 0x%02X not supported\n",
- val & AR_RADIO_SREV_MAJOR);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Radio Chip Rev 0x%02X not supported\n",
+ val & AR_RADIO_SREV_MAJOR);
return -EOPNOTSUPP;
}
@@ -510,6 +499,7 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah)
static int ath9k_hw_init_macaddr(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 sum;
int i;
u16 eeval;
@@ -518,8 +508,8 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
for (i = 0; i < 3; i++) {
eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i));
sum += eeval;
- ah->macaddr[2 * i] = eeval >> 8;
- ah->macaddr[2 * i + 1] = eeval & 0xff;
+ common->macaddr[2 * i] = eeval >> 8;
+ common->macaddr[2 * i + 1] = eeval & 0xff;
}
if (sum == 0 || sum == 0xffff * 3)
return -EADDRNOTAVAIL;
@@ -590,8 +580,10 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
if (ecode != 0)
return ecode;
- DPRINTF(ah->ah_sc, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n",
- ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah));
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CONFIG,
+ "Eeprom VER: %d, REV: %d\n",
+ ah->eep_ops->get_eeprom_ver(ah),
+ ah->eep_ops->get_eeprom_rev(ah));
ecode = ath9k_hw_rfattach(ah);
if (ecode != 0)
@@ -617,6 +609,7 @@ static bool ath9k_hw_devid_supported(u16 devid)
case AR9285_DEVID_PCIE:
case AR5416_DEVID_AR9287_PCI:
case AR5416_DEVID_AR9287_PCIE:
+ case AR9271_USB:
return true;
default:
break;
@@ -634,9 +627,8 @@ static bool ath9k_hw_macversion_supported(u32 macversion)
case AR_SREV_VERSION_9280:
case AR_SREV_VERSION_9285:
case AR_SREV_VERSION_9287:
- return true;
- /* Not yet */
case AR_SREV_VERSION_9271:
+ return true;
default:
break;
}
@@ -905,21 +897,27 @@ static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah)
int ath9k_hw_init(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int r = 0;
- if (!ath9k_hw_devid_supported(ah->hw_version.devid))
+ if (!ath9k_hw_devid_supported(ah->hw_version.devid)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unsupported device ID: 0x%0x\n",
+ ah->hw_version.devid);
return -EOPNOTSUPP;
+ }
ath9k_hw_init_defaults(ah);
ath9k_hw_init_config(ah);
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Couldn't reset chip\n");
return -EIO;
}
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
+ ath_print(common, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
return -EIO;
}
@@ -934,14 +932,14 @@ int ath9k_hw_init(struct ath_hw *ah)
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
+ ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n",
ah->config.serialize_regmode);
if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Mac Chip Rev 0x%02x.%x is not supported by "
- "this driver\n", ah->hw_version.macVersion,
- ah->hw_version.macRev);
+ ath_print(common, ATH_DBG_FATAL,
+ "Mac Chip Rev 0x%02x.%x is not supported by "
+ "this driver\n", ah->hw_version.macVersion,
+ ah->hw_version.macRev);
return -EOPNOTSUPP;
}
@@ -969,6 +967,16 @@ int ath9k_hw_init(struct ath_hw *ah)
else
ath9k_hw_disablepcie(ah);
+ /* Support for Japan ch.14 (2484) spread */
+ if (AR_SREV_9287_11_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ah->iniCckfirNormal,
+ ar9287Common_normal_cck_fir_coeff_92871_1,
+ ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1), 2);
+ INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+ ar9287Common_japan_2484_cck_fir_coeff_92871_1,
+ ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1), 2);
+ }
+
r = ath9k_hw_post_init(ah);
if (r)
return r;
@@ -979,8 +987,8 @@ int ath9k_hw_init(struct ath_hw *ah)
r = ath9k_hw_init_macaddr(ah);
if (r) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Failed to initialize MAC address\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to initialize MAC address\n");
return r;
}
@@ -991,6 +999,8 @@ int ath9k_hw_init(struct ath_hw *ah)
ath9k_init_nfcal_hist_buffer(ah);
+ common->state = ATH_HW_INITIALIZED;
+
return 0;
}
@@ -1164,7 +1174,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
{
if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "bad ack timeout %u\n", us);
ah->acktimeout = (u32) -1;
return false;
} else {
@@ -1178,7 +1189,8 @@ static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
{
if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "bad cts timeout %u\n", us);
ah->ctstimeout = (u32) -1;
return false;
} else {
@@ -1192,8 +1204,8 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
{
if (tu > 0xFFFF) {
- DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
- "bad global tx timeout %u\n", tu);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
+ "bad global tx timeout %u\n", tu);
ah->globaltxtimeout = (u32) -1;
return false;
} else {
@@ -1205,8 +1217,8 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
static void ath9k_hw_init_user_settings(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
- ah->misc_mode);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
+ ah->misc_mode);
if (ah->misc_mode != 0)
REG_WRITE(ah, AR_PCU_MISC,
@@ -1229,14 +1241,22 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid)
void ath9k_hw_detach(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (common->state <= ATH_HW_INITIALIZED)
+ goto free_hw;
+
if (!AR_SREV_9100(ah))
ath9k_hw_ani_disable(ah);
- ath9k_hw_rf_free(ah);
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+
+free_hw:
+ ath9k_hw_rf_free(ah);
kfree(ah);
ah = NULL;
}
+EXPORT_SYMBOL(ath9k_hw_detach);
/*******/
/* INI */
@@ -1298,28 +1318,29 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
u32 reg, u32 value)
{
struct base_eep_header *pBase = &(pEepData->baseEepHeader);
+ struct ath_common *common = ath9k_hw_common(ah);
switch (ah->hw_version.devid) {
case AR9280_DEVID_PCI:
if (reg == 0x7894) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ ath_print(common, ATH_DBG_EEPROM,
"ini VAL: %x EEPROM: %x\n", value,
(pBase->version & 0xff));
if ((pBase->version & 0xff) > 0x0a) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PWDCLKIND: %d\n",
- pBase->pwdclkind);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PWDCLKIND: %d\n",
+ pBase->pwdclkind);
value &= ~AR_AN_TOP2_PWDCLKIND;
value |= AR_AN_TOP2_PWDCLKIND &
(pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PWDCLKIND Earlier Rev\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "PWDCLKIND Earlier Rev\n");
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "final ini VAL: %x\n", value);
+ ath_print(common, ATH_DBG_EEPROM,
+ "final ini VAL: %x\n", value);
}
break;
}
@@ -1374,8 +1395,7 @@ static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
}
static int ath9k_hw_process_ini(struct ath_hw *ah,
- struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
+ struct ath9k_channel *chan)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
int i, regWrites = 0;
@@ -1477,7 +1497,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
}
ath9k_hw_override_ini(ah, chan);
- ath9k_hw_set_regs(ah, chan, macmode);
+ ath9k_hw_set_regs(ah, chan);
ath9k_hw_init_chain_masks(ah);
if (OLC_FOR_AR9280_20_LATER)
@@ -1491,8 +1511,8 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
(u32) regulatory->power_limit));
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "ar5416SetRfRegs failed\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "ar5416SetRfRegs failed\n");
return -EIO;
}
@@ -1697,16 +1717,14 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
REG_WRITE(ah, AR_RTC_RC, 0);
if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "RTC stuck in MAC reset\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "RTC stuck in MAC reset\n");
return false;
}
if (!AR_SREV_9100(ah))
REG_WRITE(ah, AR_RC, 0);
- ath9k_hw_init_pll(ah, NULL);
-
if (AR_SREV_9100(ah))
udelay(50);
@@ -1734,7 +1752,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
AR_RTC_STATUS_M,
AR_RTC_STATUS_ON,
AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "RTC not waking up\n");
return false;
}
@@ -1759,8 +1778,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
}
}
-static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
+static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan)
{
u32 phymode;
u32 enableDacFifo = 0;
@@ -1779,12 +1797,10 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
(chan->chanmode == CHANNEL_G_HT40PLUS))
phymode |= AR_PHY_FC_DYN2040_PRI_CH;
- if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
- phymode |= AR_PHY_FC_DYN2040_EXT_CH;
}
REG_WRITE(ah, AR_PHY_TURBO, phymode);
- ath9k_hw_set11nmac2040(ah, macmode);
+ ath9k_hw_set11nmac2040(ah);
REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
@@ -1810,17 +1826,18 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,
}
static bool ath9k_hw_channel_change(struct ath_hw *ah,
- struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
+ struct ath9k_channel *chan)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *channel = chan->chan;
u32 synthDelay, qnum;
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
if (ath9k_hw_numtxpending(ah, qnum)) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "Transmit frames pending on queue %d\n", qnum);
+ ath_print(common, ATH_DBG_QUEUE,
+ "Transmit frames pending on "
+ "queue %d\n", qnum);
return false;
}
}
@@ -1828,19 +1845,19 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Could not kill baseband RX\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Could not kill baseband RX\n");
return false;
}
- ath9k_hw_set_regs(ah, chan, macmode);
+ ath9k_hw_set_regs(ah, chan);
if (AR_SREV_9280_10_OR_LATER(ah)) {
ath9k_hw_ar9280_set_channel(ah, chan);
} else {
if (!(ath9k_hw_set_channel(ah, chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Failed to set channel\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to set channel\n");
return false;
}
}
@@ -2342,17 +2359,16 @@ static void ath9k_enable_rfkill(struct ath_hw *ah)
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 saveLedState;
- struct ath_softc *sc = ah->ah_sc;
struct ath9k_channel *curchan = ah->curchan;
u32 saveDefAntenna;
u32 macStaId1;
u64 tsf = 0;
int i, rx_chainmask, r;
- ah->extprotspacing = sc->ht_extprotspacing;
- ah->txchainmask = sc->tx_chainmask;
- ah->rxchainmask = sc->rx_chainmask;
+ ah->txchainmask = common->tx_chainmask;
+ ah->rxchainmask = common->rx_chainmask;
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return -EIO;
@@ -2369,7 +2385,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
!(AR_SREV_9280(ah) || IS_CHAN_A_5MHZ_SPACED(chan) ||
IS_CHAN_A_5MHZ_SPACED(ah->curchan))) {
- if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) {
+ if (ath9k_hw_channel_change(ah, chan)) {
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah);
return 0;
@@ -2400,7 +2416,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
if (!ath9k_hw_chip_reset(ah, chan)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n");
+ ath_print(common, ATH_DBG_FATAL, "Chip reset failed\n");
return -EINVAL;
}
@@ -2429,7 +2445,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
}
- r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
+ r = ath9k_hw_process_ini(ah, chan);
if (r)
return r;
@@ -2462,8 +2478,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_decrease_chain_power(ah, chan);
- REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr));
- REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4)
+ REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
+ REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
| macStaId1
| AR_STA_ID1_RTS_USE_DEF
| (ah->config.
@@ -2471,14 +2487,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
| ah->sta_id1_defaults);
ath9k_hw_set_operating_mode(ah, ah->opmode);
- REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
- REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
+ ath_hw_setbssidmask(common);
REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
- REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
- REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
- ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
+ ath9k_hw_write_associd(ah);
REG_WRITE(ah, AR_ISR, ~0);
@@ -2558,13 +2571,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 mask;
mask = REG_READ(ah, AR_CFG);
if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ ath_print(common, ATH_DBG_RESET,
"CFG Byte Swap Set 0x%x\n", mask);
} else {
mask =
INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
REG_WRITE(ah, AR_CFG, mask);
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ ath_print(common, ATH_DBG_RESET,
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
@@ -2577,11 +2590,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
#endif
}
- if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED)
+ if (ah->btcoex_hw.enabled)
ath9k_hw_btcoex_enable(ah);
return 0;
}
+EXPORT_SYMBOL(ath9k_hw_reset);
/************************/
/* Key Cache Management */
@@ -2592,8 +2606,8 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
u32 keyType;
if (entry >= ah->caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
return false;
}
@@ -2620,14 +2634,15 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_keyreset);
bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
{
u32 macHi, macLo;
if (entry >= ah->caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
return false;
}
@@ -2648,18 +2663,20 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_keysetmac);
bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
const struct ath9k_keyval *k,
const u8 *mac)
{
const struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
u32 key0, key1, key2, key3, key4;
u32 keyType;
if (entry >= pCap->keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "keycache entry %u out of range\n", entry);
+ ath_print(common, ATH_DBG_FATAL,
+ "keycache entry %u out of range\n", entry);
return false;
}
@@ -2669,9 +2686,9 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
break;
case ATH9K_CIPHER_AES_CCM:
if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "AES-CCM not supported by mac rev 0x%x\n",
- ah->hw_version.macRev);
+ ath_print(common, ATH_DBG_ANY,
+ "AES-CCM not supported by mac rev 0x%x\n",
+ ah->hw_version.macRev);
return false;
}
keyType = AR_KEYTABLE_TYPE_CCM;
@@ -2680,15 +2697,15 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
keyType = AR_KEYTABLE_TYPE_TKIP;
if (ATH9K_IS_MIC_ENABLED(ah)
&& entry + 64 >= pCap->keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "entry %u inappropriate for TKIP\n", entry);
+ ath_print(common, ATH_DBG_ANY,
+ "entry %u inappropriate for TKIP\n", entry);
return false;
}
break;
case ATH9K_CIPHER_WEP:
if (k->kv_len < WLAN_KEY_LEN_WEP40) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "WEP key length %u too small\n", k->kv_len);
+ ath_print(common, ATH_DBG_ANY,
+ "WEP key length %u too small\n", k->kv_len);
return false;
}
if (k->kv_len <= WLAN_KEY_LEN_WEP40)
@@ -2702,8 +2719,8 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
keyType = AR_KEYTABLE_TYPE_CLR;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "cipher %u not supported\n", k->kv_type);
+ ath_print(common, ATH_DBG_FATAL,
+ "cipher %u not supported\n", k->kv_type);
return false;
}
@@ -2845,6 +2862,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
return true;
}
+EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
{
@@ -2855,6 +2873,7 @@ bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
}
return false;
}
+EXPORT_SYMBOL(ath9k_hw_keyisvalid);
/******************************/
/* Power Management (Chipset) */
@@ -2869,8 +2888,9 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
if (!AR_SREV_9100(ah))
REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
- REG_CLR_BIT(ah, (AR_RTC_RESET),
- AR_RTC_RESET_EN);
+ if(!AR_SREV_5416(ah))
+ REG_CLR_BIT(ah, (AR_RTC_RESET),
+ AR_RTC_RESET_EN);
}
}
@@ -2902,6 +2922,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
ATH9K_RESET_POWER_ON) != true) {
return false;
}
+ ath9k_hw_init_pll(ah, NULL);
}
if (AR_SREV_9100(ah))
REG_SET_BIT(ah, AR_RTC_RESET,
@@ -2920,8 +2941,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
AR_RTC_FORCE_WAKE_EN);
}
if (i == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Failed to wakeup in %uus\n", POWER_UP_TIME / 20);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Failed to wakeup in %uus\n",
+ POWER_UP_TIME / 20);
return false;
}
}
@@ -2931,9 +2953,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
return true;
}
-static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
- enum ath9k_power_mode mode)
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int status = true, setChip = true;
static const char *modes[] = {
"AWAKE",
@@ -2945,8 +2967,8 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
if (ah->power_mode == mode)
return status;
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
- modes[ah->power_mode], modes[mode]);
+ ath_print(common, ATH_DBG_RESET, "%s -> %s\n",
+ modes[ah->power_mode], modes[mode]);
switch (mode) {
case ATH9K_PM_AWAKE:
@@ -2960,59 +2982,15 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
ath9k_set_power_network_sleep(ah, setChip);
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Unknown power mode %u\n", mode);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unknown power mode %u\n", mode);
return false;
}
ah->power_mode = mode;
return status;
}
-
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
-{
- unsigned long flags;
- bool ret;
-
- spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
- ret = ath9k_hw_setpower_nolock(ah, mode);
- spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
-
- return ret;
-}
-
-void ath9k_ps_wakeup(struct ath_softc *sc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (++sc->ps_usecount != 1)
- goto unlock;
-
- ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
-
- unlock:
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-}
-
-void ath9k_ps_restore(struct ath_softc *sc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (--sc->ps_usecount != 0)
- goto unlock;
-
- if (sc->ps_enabled &&
- !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK)))
- ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
-
- unlock:
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-}
+EXPORT_SYMBOL(ath9k_hw_setpower);
/*
* Helper for ASPM support.
@@ -3145,6 +3123,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off)
}
}
}
+EXPORT_SYMBOL(ath9k_hw_configpcipowersave);
/**********************/
/* Interrupt Handling */
@@ -3168,6 +3147,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
return false;
}
+EXPORT_SYMBOL(ath9k_hw_intrpend);
bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
{
@@ -3176,6 +3156,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
struct ath9k_hw_capabilities *pCap = &ah->caps;
u32 sync_cause = 0;
bool fatal_int = false;
+ struct ath_common *common = ath9k_hw_common(ah);
if (!AR_SREV_9100(ah)) {
if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
@@ -3249,8 +3230,8 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
}
if (isr & AR_ISR_RXORN) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "receive FIFO overrun interrupt\n");
+ ath_print(common, ATH_DBG_INTERRUPT,
+ "receive FIFO overrun interrupt\n");
}
if (!AR_SREV_9100(ah)) {
@@ -3292,25 +3273,25 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
if (fatal_int) {
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "received PCI FATAL interrupt\n");
+ ath_print(common, ATH_DBG_ANY,
+ "received PCI FATAL interrupt\n");
}
if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "received PCI PERR interrupt\n");
+ ath_print(common, ATH_DBG_ANY,
+ "received PCI PERR interrupt\n");
}
*masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
+ ath_print(common, ATH_DBG_INTERRUPT,
+ "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
REG_WRITE(ah, AR_RC, 0);
*masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+ ath_print(common, ATH_DBG_INTERRUPT,
+ "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
}
REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
@@ -3319,17 +3300,19 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_getisr);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
{
u32 omask = ah->mask_reg;
u32 mask, mask2;
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
+ ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
if (omask & ATH9K_INT_GLOBAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n");
+ ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER);
if (!AR_SREV_9100(ah)) {
@@ -3386,7 +3369,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
mask2 |= AR_IMR_S2_CST;
}
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
+ ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
REG_WRITE(ah, AR_IMR, mask);
mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
AR_IMR_S2_DTIM |
@@ -3406,7 +3389,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
}
if (ints & ATH9K_INT_GLOBAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n");
+ ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
@@ -3419,12 +3402,13 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
REG_WRITE(ah, AR_INTR_SYNC_MASK,
AR_INTR_SYNC_DEFAULT);
}
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
- REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+ ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+ REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
}
return omask;
}
+EXPORT_SYMBOL(ath9k_hw_set_interrupts);
/*******************/
/* Beacon Handling */
@@ -3467,9 +3451,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON,
- "%s: unsupported opmode: %d\n",
- __func__, ah->opmode);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BEACON,
+ "%s: unsupported opmode: %d\n",
+ __func__, ah->opmode);
return;
break;
}
@@ -3481,18 +3465,19 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
beacon_period &= ~ATH9K_BEACON_ENA;
if (beacon_period & ATH9K_BEACON_RESET_TSF) {
- beacon_period &= ~ATH9K_BEACON_RESET_TSF;
ath9k_hw_reset_tsf(ah);
}
REG_SET_BIT(ah, AR_TIMER_MODE, flags);
}
+EXPORT_SYMBOL(ath9k_hw_beaconinit);
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
const struct ath9k_beacon_state *bs)
{
u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
@@ -3518,10 +3503,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
else
nextTbtt = bs->bs_nexttbtt;
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
+ ath_print(common, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
+ ath_print(common, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
+ ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
+ ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
REG_WRITE(ah, AR_NEXT_DTIM,
TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
@@ -3549,6 +3534,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
/* TSF Out of Range Threshold */
REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
}
+EXPORT_SYMBOL(ath9k_hw_set_sta_beacon_timers);
/*******************/
/* HW Capabilities */
@@ -3558,7 +3544,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
u16 capField = 0, eeval;
@@ -3579,8 +3566,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
regulatory->current_rd += 5;
else if (regulatory->current_rd == 0x41)
regulatory->current_rd = 0x43;
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "regdomain mapped to 0x%x\n", regulatory->current_rd);
+ ath_print(common, ATH_DBG_REGULATORY,
+ "regdomain mapped to 0x%x\n", regulatory->current_rd);
}
eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
@@ -3719,7 +3706,10 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
}
- pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
+ /* Advertise midband for AR5416 with FCC midband set in eeprom */
+ if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) &&
+ AR_SREV_5416(ah))
+ pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
pCap->num_antcfg_5ghz =
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
@@ -3727,18 +3717,18 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
if (AR_SREV_9280_10_OR_LATER(ah) &&
- ath_btcoex_supported(ah->hw_version.subsysid)) {
- btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO;
- btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
+ ath9k_hw_btcoex_supported(ah)) {
+ btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
+ btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
if (AR_SREV_9285(ah)) {
- btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE;
- btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO;
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+ btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO;
} else {
- btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE;
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
}
} else {
- btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE;
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
}
}
@@ -3812,6 +3802,7 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
return false;
}
}
+EXPORT_SYMBOL(ath9k_hw_getcapability);
bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
u32 capability, u32 setting, int *status)
@@ -3845,6 +3836,7 @@ bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
return false;
}
}
+EXPORT_SYMBOL(ath9k_hw_setcapability);
/****************************/
/* GPIO / RFKILL / Antennae */
@@ -3882,7 +3874,7 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
{
u32 gpio_shift;
- ASSERT(gpio < ah->caps.num_gpio_pins);
+ BUG_ON(gpio >= ah->caps.num_gpio_pins);
gpio_shift = gpio << 1;
@@ -3891,6 +3883,7 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
(AR_GPIO_OE_OUT_DRV << gpio_shift));
}
+EXPORT_SYMBOL(ath9k_hw_cfg_gpio_input);
u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
{
@@ -3909,6 +3902,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
else
return MS_REG_READ(AR, gpio) != 0;
}
+EXPORT_SYMBOL(ath9k_hw_gpio_get);
void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
u32 ah_signal_type)
@@ -3924,22 +3918,26 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
(AR_GPIO_OE_OUT_DRV << gpio_shift));
}
+EXPORT_SYMBOL(ath9k_hw_cfg_output);
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
{
REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
AR_GPIO_BIT(gpio));
}
+EXPORT_SYMBOL(ath9k_hw_set_gpio);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
{
return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
}
+EXPORT_SYMBOL(ath9k_hw_getdefantenna);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
{
REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
}
+EXPORT_SYMBOL(ath9k_hw_setantenna);
bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
enum ath9k_ant_setting settings,
@@ -4002,6 +4000,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah)
return bits;
}
+EXPORT_SYMBOL(ath9k_hw_getrxfilter);
void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
{
@@ -4023,19 +4022,30 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
REG_WRITE(ah, AR_RXCFG,
REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
}
+EXPORT_SYMBOL(ath9k_hw_setrxfilter);
bool ath9k_hw_phy_disable(struct ath_hw *ah)
{
- return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+ return false;
+
+ ath9k_hw_init_pll(ah, NULL);
+ return true;
}
+EXPORT_SYMBOL(ath9k_hw_phy_disable);
bool ath9k_hw_disable(struct ath_hw *ah)
{
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return false;
- return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD))
+ return false;
+
+ ath9k_hw_init_pll(ah, NULL);
+ return true;
}
+EXPORT_SYMBOL(ath9k_hw_disable);
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
{
@@ -4052,35 +4062,36 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
min((u32) MAX_RATE_POWER,
(u32) regulatory->power_limit));
}
+EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
{
- memcpy(ah->macaddr, mac, ETH_ALEN);
+ memcpy(ath9k_hw_common(ah)->macaddr, mac, ETH_ALEN);
}
+EXPORT_SYMBOL(ath9k_hw_setmac);
void ath9k_hw_setopmode(struct ath_hw *ah)
{
ath9k_hw_set_operating_mode(ah, ah->opmode);
}
+EXPORT_SYMBOL(ath9k_hw_setopmode);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1)
{
REG_WRITE(ah, AR_MCAST_FIL0, filter0);
REG_WRITE(ah, AR_MCAST_FIL1, filter1);
}
+EXPORT_SYMBOL(ath9k_hw_setmcastfilter);
-void ath9k_hw_setbssidmask(struct ath_softc *sc)
+void ath9k_hw_write_associd(struct ath_hw *ah)
{
- REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
- REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
-}
+ struct ath_common *common = ath9k_hw_common(ah);
-void ath9k_hw_write_associd(struct ath_softc *sc)
-{
- REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
- REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
- ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
+ REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(common->curbssid));
+ REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(common->curbssid + 4) |
+ ((common->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
}
+EXPORT_SYMBOL(ath9k_hw_write_associd);
u64 ath9k_hw_gettsf64(struct ath_hw *ah)
{
@@ -4091,24 +4102,25 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah)
return tsf;
}
+EXPORT_SYMBOL(ath9k_hw_gettsf64);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
{
REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
}
+EXPORT_SYMBOL(ath9k_hw_settsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah)
{
- ath9k_ps_wakeup(ah->ah_sc);
if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
AH_TSF_WRITE_TIMEOUT))
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
- ath9k_ps_restore(ah->ah_sc);
}
+EXPORT_SYMBOL(ath9k_hw_reset_tsf);
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
{
@@ -4117,11 +4129,13 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
else
ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
}
+EXPORT_SYMBOL(ath9k_hw_set_tsfadjust);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "bad slot time %u\n", us);
ah->slottime = (u32) -1;
return false;
} else {
@@ -4130,13 +4144,14 @@ bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
return true;
}
}
+EXPORT_SYMBOL(ath9k_hw_setslottime);
-void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
+void ath9k_hw_set11nmac2040(struct ath_hw *ah)
{
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
u32 macmode;
- if (mode == ATH9K_HT_MACMODE_2040 &&
- !ah->config.cwm_ignore_extcca)
+ if (conf_is_ht40(conf) && !ah->config.cwm_ignore_extcca)
macmode = AR_2040_JOINED_RX_CLEAR;
else
macmode = 0;
@@ -4193,6 +4208,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah)
{
return REG_READ(ah, AR_TSF_L32);
}
+EXPORT_SYMBOL(ath9k_hw_gettsf32);
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
@@ -4206,8 +4222,9 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
if (timer == NULL) {
- printk(KERN_DEBUG "Failed to allocate memory"
- "for hw timer[%d]\n", timer_index);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Failed to allocate memory"
+ "for hw timer[%d]\n", timer_index);
return NULL;
}
@@ -4220,10 +4237,12 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
return timer;
}
+EXPORT_SYMBOL(ath_gen_timer_alloc);
-void ath_gen_timer_start(struct ath_hw *ah,
- struct ath_gen_timer *timer,
- u32 timer_next, u32 timer_period)
+void ath9k_hw_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next,
+ u32 timer_period)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
u32 tsf;
@@ -4234,8 +4253,9 @@ void ath_gen_timer_start(struct ath_hw *ah,
tsf = ath9k_hw_gettsf32(ah);
- DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x"
- "timer_next %x\n", tsf, timer_period, timer_next);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_HWTIMER,
+ "curent tsf %x period %x"
+ "timer_next %x\n", tsf, timer_period, timer_next);
/*
* Pull timer_next forward if the current TSF already passed it
@@ -4258,15 +4278,10 @@ void ath_gen_timer_start(struct ath_hw *ah,
REG_SET_BIT(ah, AR_IMR_S5,
(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
-
- if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) {
- ath9k_hw_set_interrupts(ah, 0);
- ah->ah_sc->imask |= ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
- }
}
+EXPORT_SYMBOL(ath9k_hw_gen_timer_start);
-void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
@@ -4285,14 +4300,8 @@ void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
-
- /* if no timer is enabled, turn off interrupt mask */
- if (timer_table->timer_mask.val == 0) {
- ath9k_hw_set_interrupts(ah, 0);
- ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
- }
}
+EXPORT_SYMBOL(ath9k_hw_gen_timer_stop);
void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
{
@@ -4302,6 +4311,7 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
timer_table->timers[timer->index] = NULL;
kfree(timer);
}
+EXPORT_SYMBOL(ath_gen_timer_free);
/*
* Generic Timer Interrupts handling
@@ -4310,6 +4320,7 @@ void ath_gen_timer_isr(struct ath_hw *ah)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
struct ath_gen_timer *timer;
+ struct ath_common *common = ath9k_hw_common(ah);
u32 trigger_mask, thresh_mask, index;
/* get hardware generic timer interrupt status */
@@ -4324,8 +4335,8 @@ void ath_gen_timer_isr(struct ath_hw *ah)
index = rightmost_index(timer_table, &thresh_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
- DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
- "TSF overflow for Gen timer %d\n", index);
+ ath_print(common, ATH_DBG_HWTIMER,
+ "TSF overflow for Gen timer %d\n", index);
timer->overflow(timer->arg);
}
@@ -4333,21 +4344,9 @@ void ath_gen_timer_isr(struct ath_hw *ah)
index = rightmost_index(timer_table, &trigger_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
- DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
- "Gen timer[%d] trigger\n", index);
+ ath_print(common, ATH_DBG_HWTIMER,
+ "Gen timer[%d] trigger\n", index);
timer->trigger(timer->arg);
}
}
-
-/*
- * Primitive to disable ASPM
- */
-void ath_pcie_aspm_disable(struct ath_softc *sc)
-{
- struct pci_dev *pdev = to_pci_dev(sc->dev);
- u8 aspm;
-
- pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
- aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1);
- pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
-}
+EXPORT_SYMBOL(ath_gen_timer_isr);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index b8923457182..cdaec526db3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -27,17 +27,24 @@
#include "calib.h"
#include "reg.h"
#include "phy.h"
+#include "btcoex.h"
#include "../regd.h"
+#include "../debug.h"
#define ATHEROS_VENDOR_ID 0x168c
+
#define AR5416_DEVID_PCI 0x0023
#define AR5416_DEVID_PCIE 0x0024
#define AR9160_DEVID_PCI 0x0027
#define AR9280_DEVID_PCI 0x0029
#define AR9280_DEVID_PCIE 0x002a
#define AR9285_DEVID_PCIE 0x002b
+
#define AR5416_AR9100_DEVID 0x000b
+
+#define AR9271_USB 0x9271
+
#define AR_SUBVENDOR_ID_NOG 0x0e11
#define AR_SUBVENDOR_ID_NEW_A 0x7065
#define AR5416_MAGIC 0x19641014
@@ -49,9 +56,18 @@
#define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa
#define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab
+#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
+
+#define ATH_DEFAULT_NOISE_FLOOR -95
+
+#define ATH9K_RSSI_BAD 0x80
+
/* Register read/write primitives */
-#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
-#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
+#define REG_WRITE(_ah, _reg, _val) \
+ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
+
+#define REG_READ(_ah, _reg) \
+ ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
@@ -91,7 +107,7 @@
#define AR_GPIO_BIT(_gpio) (1 << (_gpio))
#define BASE_ACTIVATE_DELAY 100
-#define RTC_PLL_SETTLE_DELAY 1000
+#define RTC_PLL_SETTLE_DELAY 100
#define COEF_SCALE_S 24
#define HT40_CHANNEL_CENTER_SHIFT 10
@@ -433,7 +449,8 @@ struct ath_gen_timer_table {
};
struct ath_hw {
- struct ath_softc *ah_sc;
+ struct ieee80211_hw *hw;
+ struct ath_common common;
struct ath9k_hw_version hw_version;
struct ath9k_ops_config config;
struct ath9k_hw_capabilities caps;
@@ -450,7 +467,6 @@ struct ath_hw {
bool sw_mgmt_crypto;
bool is_pciexpress;
- u8 macaddr[ETH_ALEN];
u16 tx_trig_level;
u16 rfsilent;
u32 rfkill_gpio;
@@ -553,8 +569,10 @@ struct ath_hw {
int firpwr[5];
enum ath9k_ani_cmd ani_function;
+ /* Bluetooth coexistance */
+ struct ath_btcoex_hw btcoex_hw;
+
u32 intr_txqs;
- enum ath9k_ht_extprotspacing extprotspacing;
u8 txchainmask;
u8 rxchainmask;
@@ -578,12 +596,24 @@ struct ath_hw {
struct ar5416IniArray iniModesAdditional;
struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray iniModesTxGain;
+ struct ar5416IniArray iniCckfirNormal;
+ struct ar5416IniArray iniCckfirJapan2484;
u32 intr_gen_timer_trigger;
u32 intr_gen_timer_thresh;
struct ath_gen_timer_table hw_gen_timers;
};
+static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
+{
+ return &ah->common;
+}
+
+static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
+{
+ return &(ath9k_hw_common(ah)->regulatory);
+}
+
/* Initialization, Detach, Reset */
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
void ath9k_hw_detach(struct ath_hw *ah);
@@ -637,19 +667,20 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac);
void ath9k_hw_setopmode(struct ath_hw *ah);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
-void ath9k_hw_setbssidmask(struct ath_softc *sc);
-void ath9k_hw_write_associd(struct ath_softc *sc);
+void ath9k_hw_setbssidmask(struct ath_hw *ah);
+void ath9k_hw_write_associd(struct ath_hw *ah);
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah);
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
-void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode);
+void ath9k_hw_set11nmac2040(struct ath_hw *ah);
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
const struct ath9k_beacon_state *bs);
-bool ath9k_hw_setpower(struct ath_hw *ah,
- enum ath9k_power_mode mode);
+
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
+
void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off);
/* Interrupt Handling */
@@ -663,9 +694,12 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*overflow)(void *),
void *arg,
u8 timer_index);
-void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer,
- u32 timer_next, u32 timer_period);
-void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
+void ath9k_hw_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next,
+ u32 timer_period);
+void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
+
void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
void ath_gen_timer_isr(struct ath_hw *hw);
u32 ath9k_hw_gettsf32(struct ath_hw *ah);
@@ -674,5 +708,4 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah);
#define ATH_PCIE_CAP_LINK_L0S 1
#define ATH_PCIE_CAP_LINK_L1 2
-void ath_pcie_aspm_disable(struct ath_softc *sc);
#endif
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index 8622265a030..3ee6658d809 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -21,6 +21,8 @@ static const u32 ar5416Modes[][6] = {
{ 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
{ 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
{ 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+ { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
+ { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
{ 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
{ 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
{ 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
@@ -31,11 +33,11 @@ static const u32 ar5416Modes[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de },
+ { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de },
{ 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
+ { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
- { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
{ 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
@@ -46,10 +48,10 @@ static const u32 ar5416Modes[][6] = {
{ 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 },
- { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
+ { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
{ 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c },
+ { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c },
{ 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
@@ -199,7 +201,6 @@ static const u32 ar5416Common[][2] = {
{ 0x00008110, 0x00000168 },
{ 0x00008118, 0x000100aa },
{ 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04800 },
{ 0x00008124, 0x00000000 },
{ 0x00008128, 0x00000000 },
{ 0x0000812c, 0x00000000 },
@@ -215,7 +216,6 @@ static const u32 ar5416Common[][2] = {
{ 0x00008178, 0x00000100 },
{ 0x0000817c, 0x00000000 },
{ 0x000081c4, 0x00000000 },
- { 0x000081d0, 0x00003210 },
{ 0x000081ec, 0x00000000 },
{ 0x000081f0, 0x00000000 },
{ 0x000081f4, 0x00000000 },
@@ -246,6 +246,7 @@ static const u32 ar5416Common[][2] = {
{ 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8000010 },
{ 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 },
@@ -406,9 +407,9 @@ static const u32 ar5416Common[][2] = {
{ 0x0000a25c, 0x0f0f0f01 },
{ 0x0000a260, 0xdfa91f01 },
{ 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
- { 0x0000c26c, 0x0ebae9c6 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
+ { 0x0000c26c, 0x0e79e5c6 },
{ 0x0000d270, 0x00820820 },
{ 0x0000a278, 0x1ce739ce },
{ 0x0000a27c, 0x051701ce },
@@ -2551,26 +2552,27 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
{ 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
{ 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
{ 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
{ 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e },
+ { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
{ 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
{ 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
{ 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016 },
{ 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
{ 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
{ 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
{ 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
{ 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
@@ -2585,8 +2587,10 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000 },
{ 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
{ 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000 },
{ 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
};
@@ -2813,7 +2817,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00009958, 0x2108ecff },
{ 0x00009940, 0x14750604 },
{ 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
{ 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
@@ -2849,7 +2852,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000a22c, 0x233f7180 },
{ 0x0000a234, 0x20202020 },
{ 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c88000 },
{ 0x0000a240, 0x38490a20 },
{ 0x0000a244, 0x00007bb6 },
{ 0x0000a248, 0x0fff3ffc },
@@ -2859,8 +2861,8 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000a25c, 0x0f0f0f01 },
{ 0x0000a260, 0xdfa91f01 },
{ 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
{ 0x0000d270, 0x00820820 },
{ 0x0000a278, 0x1ce739ce },
{ 0x0000d35c, 0x07ffffef },
@@ -2874,7 +2876,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000d37c, 0x7fffffe2 },
{ 0x0000d380, 0x7f3c7bba },
{ 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
{ 0x0000a38c, 0x20202020 },
{ 0x0000a390, 0x20202020 },
{ 0x0000a394, 0x1ce739ce },
@@ -2940,7 +2941,7 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
{ 0x0000801c, 0x148ec02b, 0x148ec057 },
{ 0x00008318, 0x000044c0, 0x00008980 },
{ 0x00009820, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000f0f, 0x00000f0f },
+ { 0x00009824, 0x01000f0f, 0x01000f0f },
{ 0x00009828, 0x0b020001, 0x0b020001 },
{ 0x00009834, 0x00000f0f, 0x00000f0f },
{ 0x00009844, 0x03721821, 0x03721821 },
@@ -3348,6 +3349,8 @@ static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
};
static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
+ { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 },
{ 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 },
@@ -3376,11 +3379,11 @@ static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
{ 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 },
{ 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
{ 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
- { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
};
static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
+ { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
{ 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
@@ -3409,8 +3412,6 @@ static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
{ 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 },
{ 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
{ 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
- { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
};
static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
@@ -5918,9 +5919,6 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x000099ec, 0x0cc80caa },
{ 0x000099f0, 0x00000000 },
{ 0x000099fc, 0x00001042 },
- { 0x0000a1f4, 0x00fffeff },
- { 0x0000a1f8, 0x00f5f9ff },
- { 0x0000a1fc, 0xb79f6427 },
{ 0x0000a208, 0x803e4788 },
{ 0x0000a210, 0x4080a333 },
{ 0x0000a214, 0x40206c10 },
@@ -5980,7 +5978,7 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x0000b3f4, 0x00000000 },
{ 0x0000a7d8, 0x000003f1 },
{ 0x00007800, 0x00000800 },
- { 0x00007804, 0x6c35ffc2 },
+ { 0x00007804, 0x6c35ffd2 },
{ 0x00007808, 0x6db6c000 },
{ 0x0000780c, 0x6db6cb30 },
{ 0x00007810, 0x6db6cb6c },
@@ -6000,7 +5998,7 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x00007848, 0x934934a8 },
{ 0x00007850, 0x00000000 },
{ 0x00007854, 0x00000800 },
- { 0x00007858, 0x6c35ffc2 },
+ { 0x00007858, 0x6c35ffd2 },
{ 0x0000785c, 0x6db6c000 },
{ 0x00007860, 0x6db6cb30 },
{ 0x00007864, 0x6db6cb6c },
@@ -6027,6 +6025,22 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x000078b8, 0x2a850160 },
};
+/*
+ * For Japanese regulatory requirements, 2484 MHz requires the following three
+ * registers be programmed differently from the channel between 2412 and 2472 MHz.
+ */
+static const u_int32_t ar9287Common_normal_cck_fir_coeff_92871_1[][2] = {
+ { 0x0000a1f4, 0x00fffeff },
+ { 0x0000a1f8, 0x00f5f9ff },
+ { 0x0000a1fc, 0xb79f6427 },
+};
+
+static const u_int32_t ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = {
+ { 0x0000a1f4, 0x00000000 },
+ { 0x0000a1f8, 0xefff0301 },
+ { 0x0000a1fc, 0xca9228ee },
+};
+
static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 800bfab9463..46466ffebcb 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -14,16 +14,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
struct ath9k_tx_queue_info *qi)
{
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
- ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
- ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
- ah->txurn_interrupt_mask);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
+ "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+ ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
+ ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
+ ah->txurn_interrupt_mask);
REG_WRITE(ah, AR_IMR_S0,
SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
@@ -39,17 +39,21 @@ u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
{
return REG_READ(ah, AR_QTXDP(q));
}
+EXPORT_SYMBOL(ath9k_hw_gettxbuf);
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
{
REG_WRITE(ah, AR_QTXDP(q), txdp);
}
+EXPORT_SYMBOL(ath9k_hw_puttxbuf);
void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
{
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_QUEUE,
+ "Enable TXE on queue: %u\n", q);
REG_WRITE(ah, AR_Q_TXE, 1 << q);
}
+EXPORT_SYMBOL(ath9k_hw_txstart);
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
{
@@ -64,6 +68,7 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
return npend;
}
+EXPORT_SYMBOL(ath9k_hw_numtxpending);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
{
@@ -93,27 +98,28 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
return newLevel != curLevel;
}
+EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
{
#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
#define ATH9K_TIME_QUANTUM 100 /* usec */
-
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
u32 tsfLow, j, wait;
u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
+ "inactive queue: %u\n", q);
return false;
}
@@ -126,9 +132,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
}
if (ath9k_hw_numtxpending(ah, q)) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: Num of pending TX Frames %d on Q %d\n",
- __func__, ath9k_hw_numtxpending(ah, q), q);
+ ath_print(common, ATH_DBG_QUEUE,
+ "%s: Num of pending TX Frames %d on Q %d\n",
+ __func__, ath9k_hw_numtxpending(ah, q), q);
for (j = 0; j < 2; j++) {
tsfLow = REG_READ(ah, AR_TSF_L32);
@@ -142,9 +148,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
break;
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "TSF has moved while trying to set "
- "quiet time TSF: 0x%08x\n", tsfLow);
+ ath_print(common, ATH_DBG_QUEUE,
+ "TSF has moved while trying to set "
+ "quiet time TSF: 0x%08x\n", tsfLow);
}
REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
@@ -155,9 +161,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
wait = wait_time;
while (ath9k_hw_numtxpending(ah, q)) {
if ((--wait) == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "Failed to stop TX DMA in 100 "
- "msec after killing last frame\n");
+ ath_print(common, ATH_DBG_QUEUE,
+ "Failed to stop TX DMA in 100 "
+ "msec after killing last frame\n");
break;
}
udelay(ATH9K_TIME_QUANTUM);
@@ -172,6 +178,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
#undef ATH9K_TX_STOP_DMA_TIMEOUT
#undef ATH9K_TIME_QUANTUM
}
+EXPORT_SYMBOL(ath9k_hw_stoptxdma);
void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 segLen, bool firstSeg,
@@ -198,6 +205,7 @@ void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
}
+EXPORT_SYMBOL(ath9k_hw_filltxdesc);
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -209,6 +217,7 @@ void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
}
+EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -284,6 +293,7 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
return 0;
}
+EXPORT_SYMBOL(ath9k_hw_txprocdesc);
void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
@@ -319,6 +329,7 @@ void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_ctl11 = 0;
}
}
+EXPORT_SYMBOL(ath9k_hw_set11n_txdesc);
void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
struct ath_desc *lastds,
@@ -374,6 +385,7 @@ void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
last_ads->ds_ctl2 = ads->ds_ctl2;
last_ads->ds_ctl3 = ads->ds_ctl3;
}
+EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario);
void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
u32 aggrLen)
@@ -384,6 +396,7 @@ void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_ctl6 &= ~AR_AggrLen;
ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
}
+EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first);
void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
u32 numDelims)
@@ -398,6 +411,7 @@ void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
ctl6 |= SM(numDelims, AR_PadDelim);
ads->ds_ctl6 = ctl6;
}
+EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle);
void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -407,6 +421,7 @@ void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
ads->ds_ctl1 &= ~AR_MoreAggr;
ads->ds_ctl6 &= ~AR_PadDelim;
}
+EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last);
void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -414,6 +429,7 @@ void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
}
+EXPORT_SYMBOL(ath9k_hw_clr11n_aggr);
void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
u32 burstDuration)
@@ -423,6 +439,7 @@ void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_ctl2 &= ~AR_BurstDur;
ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
}
+EXPORT_SYMBOL(ath9k_hw_set11n_burstduration);
void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
u32 vmf)
@@ -440,28 +457,30 @@ void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
*txqs &= ah->intr_txqs;
ah->intr_txqs &= ~(*txqs);
}
+EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs);
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
const struct ath9k_tx_queue_info *qinfo)
{
u32 cw;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
+ "inactive queue: %u\n", q);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
qi->tqi_ver = qinfo->tqi_ver;
qi->tqi_subtype = qinfo->tqi_subtype;
@@ -510,23 +529,25 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
return true;
}
+EXPORT_SYMBOL(ath9k_hw_set_txq_props);
bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
struct ath9k_tx_queue_info *qinfo)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
+ "inactive queue: %u\n", q);
return false;
}
@@ -547,10 +568,12 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
return true;
}
+EXPORT_SYMBOL(ath9k_hw_get_txq_props);
int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
const struct ath9k_tx_queue_info *qinfo)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info *qi;
struct ath9k_hw_capabilities *pCap = &ah->caps;
int q;
@@ -574,23 +597,23 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
ATH9K_TX_QUEUE_INACTIVE)
break;
if (q == pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "No available TX queue\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "No available TX queue\n");
return -1;
}
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n",
- type);
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid TX queue type: %u\n", type);
return -1;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
qi = &ah->txq[q];
if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "TX queue: %u already active\n", q);
+ ath_print(common, ATH_DBG_FATAL,
+ "TX queue: %u already active\n", q);
return -1;
}
memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -613,25 +636,27 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
return q;
}
+EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
+ "inactive queue: %u\n", q);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
ah->txok_interrupt_mask &= ~(1 << q);
@@ -643,28 +668,30 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
struct ath9k_tx_queue_info *qi;
u32 cwMin, chanCwMin, value;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
+ "inactive queue: %u\n", q);
return true;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
if (chan && IS_CHAN_B(chan))
@@ -799,6 +826,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_resettxqueue);
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 pa, struct ath_desc *nds, u64 tsf)
@@ -880,6 +908,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
return 0;
}
+EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags)
@@ -895,6 +924,7 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
memset(&(ads->u), 0, sizeof(ads->u));
}
+EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
{
@@ -911,8 +941,9 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
AR_DIAG_RX_ABORT));
reg = REG_READ(ah, AR_OBS_BUS_1);
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "RX failed to go idle in 10 ms RXSM=0x%x\n", reg);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "RX failed to go idle in 10 ms RXSM=0x%x\n",
+ reg);
return false;
}
@@ -923,16 +954,19 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_setrxabort);
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
{
REG_WRITE(ah, AR_RXDP, rxdp);
}
+EXPORT_SYMBOL(ath9k_hw_putrxbuf);
void ath9k_hw_rxena(struct ath_hw *ah)
{
REG_WRITE(ah, AR_CR, AR_CR_RXE);
}
+EXPORT_SYMBOL(ath9k_hw_rxena);
void ath9k_hw_startpcureceive(struct ath_hw *ah)
{
@@ -942,6 +976,7 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah)
REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
}
+EXPORT_SYMBOL(ath9k_hw_startpcureceive);
void ath9k_hw_stoppcurecv(struct ath_hw *ah)
{
@@ -949,12 +984,13 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah)
ath9k_hw_disable_mib_counters(ah);
}
+EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
{
#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
#define AH_RX_TIME_QUANTUM 100 /* usec */
-
+ struct ath_common *common = ath9k_hw_common(ah);
int i;
REG_WRITE(ah, AR_CR, AR_CR_RXD);
@@ -967,12 +1003,12 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
}
if (i == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "DMA failed to stop in %d ms "
- "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
- AH_RX_STOP_DMA_TIMEOUT / 1000,
- REG_READ(ah, AR_CR),
- REG_READ(ah, AR_DIAG_SW));
+ ath_print(common, ATH_DBG_FATAL,
+ "DMA failed to stop in %d ms "
+ "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+ AH_RX_STOP_DMA_TIMEOUT / 1000,
+ REG_READ(ah, AR_CR),
+ REG_READ(ah, AR_DIAG_SW));
return false;
} else {
return true;
@@ -981,3 +1017,17 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
#undef AH_RX_TIME_QUANTUM
#undef AH_RX_STOP_DMA_TIMEOUT
}
+EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
+
+int ath9k_hw_beaconq_setup(struct ath_hw *ah)
+{
+ struct ath9k_tx_queue_info qi;
+
+ memset(&qi, 0, sizeof(qi));
+ qi.tqi_aifs = 1;
+ qi.tqi_cwmin = 0;
+ qi.tqi_cwmax = 0;
+ /* NB: don't enable any interrupts */
+ return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
+}
+EXPORT_SYMBOL(ath9k_hw_beaconq_setup);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index f56e77da6c3..fefb65dafb1 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -614,16 +614,6 @@ enum ath9k_cipher {
ATH9K_CIPHER_MIC = 127
};
-enum ath9k_ht_macmode {
- ATH9K_HT_MACMODE_20 = 0,
- ATH9K_HT_MACMODE_2040 = 1,
-};
-
-enum ath9k_ht_extprotspacing {
- ATH9K_HT_EXTPROTSPACING_20 = 0,
- ATH9K_HT_EXTPROTSPACING_25 = 1,
-};
-
struct ath_hw;
struct ath9k_channel;
struct ath_rate_table;
@@ -677,5 +667,6 @@ void ath9k_hw_rxena(struct ath_hw *ah);
void ath9k_hw_startpcureceive(struct ath_hw *ah);
void ath9k_hw_stoppcurecv(struct ath_hw *ah);
bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
+int ath9k_hw_beaconq_setup(struct ath_hw *ah);
#endif /* MAC_H */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 52bed89063d..69cf702b18c 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -16,6 +16,7 @@
#include <linux/nl80211.h>
#include "ath9k.h"
+#include "btcoex.h"
static char *dev_info = "ath9k";
@@ -28,6 +29,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
+module_param_named(debug, ath9k_debug, uint, 0);
+MODULE_PARM_DESC(debug, "Debugging mask");
+
/* We use the hw_value as an index into our private channel structure */
#define CHAN2G(_freq, _idx) { \
@@ -224,8 +229,9 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
}
sband->n_bitrates++;
- DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n",
- rate[i].bitrate / 10, rate[i].hw_value);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Rate: %2dMbps, ratecode: %2d\n",
+ rate[i].bitrate / 10, rate[i].hw_value);
}
}
@@ -242,6 +248,51 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc,
return channel;
}
+static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ ret = ath9k_hw_setpower(sc->sc_ah, mode);
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+
+ return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (++sc->ps_usecount != 1)
+ goto unlock;
+
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (--sc->ps_usecount != 0)
+ goto unlock;
+
+ if (sc->ps_enabled &&
+ !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+ SC_OP_WAIT_FOR_CAB |
+ SC_OP_WAIT_FOR_PSPOLL_DATA |
+ SC_OP_WAIT_FOR_TX_ACK)))
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
/*
* Set/change channels. If the channel is really being changed, it's done
* by reseting the chip. To accomplish this we must first cleanup any pending
@@ -251,6 +302,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *hchan)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
bool fastcc = true, stopped;
struct ieee80211_channel *channel = hw->conf.channel;
int r;
@@ -280,19 +333,19 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
fastcc = false;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "(%u MHz) -> (%u MHz), chanwidth: %d\n",
- sc->sc_ah->curchan->channel,
- channel->center_freq, sc->tx_chan_width);
+ ath_print(common, ATH_DBG_CONFIG,
+ "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
+ sc->sc_ah->curchan->channel,
+ channel->center_freq, conf_is_ht40(conf));
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, hchan, fastcc);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset channel (%u Mhz) "
- "reset status %d\n",
- channel->center_freq, r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset channel (%u Mhz) "
+ "reset status %d\n",
+ channel->center_freq, r);
spin_unlock_bh(&sc->sc_resetlock);
goto ps_restore;
}
@@ -301,8 +354,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
sc->sc_flags &= ~SC_OP_FULL_RESET;
if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to restart recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to restart recv logic\n");
r = -EIO;
goto ps_restore;
}
@@ -327,6 +380,7 @@ static void ath_ani_calibrate(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
bool longcal = false;
bool shortcal = false;
bool aniflag = false;
@@ -353,7 +407,7 @@ static void ath_ani_calibrate(unsigned long data)
/* Long calibration runs independently of short calibration. */
if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
longcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
+ ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
sc->ani.longcal_timer = timestamp;
}
@@ -361,7 +415,8 @@ static void ath_ani_calibrate(unsigned long data)
if (!sc->ani.caldone) {
if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) {
shortcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies);
+ ath_print(common, ATH_DBG_ANI,
+ "shortcal @%lu\n", jiffies);
sc->ani.shortcal_timer = timestamp;
sc->ani.resetcal_timer = timestamp;
}
@@ -388,16 +443,21 @@ static void ath_ani_calibrate(unsigned long data)
/* Perform calibration if necessary */
if (longcal || shortcal) {
- sc->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan,
- sc->rx_chainmask, longcal);
+ sc->ani.caldone =
+ ath9k_hw_calibrate(ah,
+ ah->curchan,
+ common->rx_chainmask,
+ longcal);
if (longcal)
sc->ani.noise_floor = ath9k_hw_getchan_noise(ah,
ah->curchan);
- DPRINTF(sc, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n",
- ah->curchan->channel, ah->curchan->channelFlags,
- sc->ani.noise_floor);
+ ath_print(common, ATH_DBG_ANI,
+ " calibrate chan %u/%x nf: %d\n",
+ ah->curchan->channel,
+ ah->curchan->channelFlags,
+ sc->ani.noise_floor);
}
}
@@ -439,17 +499,22 @@ static void ath_start_ani(struct ath_softc *sc)
*/
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
- (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) {
- sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
- sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
+ (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE)) {
+ common->tx_chainmask = ah->caps.tx_chainmask;
+ common->rx_chainmask = ah->caps.rx_chainmask;
} else {
- sc->tx_chainmask = 1;
- sc->rx_chainmask = 1;
+ common->tx_chainmask = 1;
+ common->rx_chainmask = 1;
}
- DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n",
- sc->tx_chainmask, sc->rx_chainmask);
+ ath_print(common, ATH_DBG_CONFIG,
+ "tx chmask: %d, rx chmask: %d\n",
+ common->tx_chainmask,
+ common->rx_chainmask);
}
static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
@@ -478,6 +543,9 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
static void ath9k_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
u32 status = sc->intrstatus;
ath9k_ps_wakeup(sc);
@@ -502,16 +570,17 @@ static void ath9k_tasklet(unsigned long data)
* TSF sync does not look correct; remain awake to sync with
* the next Beacon.
*/
- DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n");
+ ath_print(common, ATH_DBG_PS,
+ "TSFOOR - Sync with next Beacon\n");
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
}
- if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah);
/* re-enable hardware interrupt */
- ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+ ath9k_hw_set_interrupts(ah, sc->imask);
ath9k_ps_restore(sc);
}
@@ -602,7 +671,7 @@ irqreturn_t ath_isr(int irq, void *dev)
if (status & ATH9K_INT_TIM_TIMER) {
/* Clear RxAbort bit so that we can
* receive frames */
- ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
+ ath9k_setpower(sc, ATH9K_PM_AWAKE);
ath9k_hw_setrxabort(sc->sc_ah, 0);
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
}
@@ -702,8 +771,8 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
/* TX MIC entry failed. No need to proceed further */
- DPRINTF(sc, ATH_DBG_FATAL,
- "Setting TX MIC Key Failed\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Setting TX MIC Key Failed\n");
return 0;
}
@@ -890,6 +959,7 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
static void setup_ht_cap(struct ath_softc *sc,
struct ieee80211_sta_ht_cap *ht_info)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u8 tx_streams, rx_streams;
ht_info->ht_supported = true;
@@ -903,12 +973,15 @@ static void setup_ht_cap(struct ath_softc *sc,
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2;
- rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2;
+ tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
+ 1 : 2;
+ rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
+ 1 : 2;
if (tx_streams != rx_streams) {
- DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n",
- tx_streams, rx_streams);
+ ath_print(common, ATH_DBG_CONFIG,
+ "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
ht_info->mcs.tx_params |= ((tx_streams - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
@@ -925,14 +998,17 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
if (bss_conf->assoc) {
- DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
- bss_conf->aid, sc->curbssid);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
/* New association, store aid */
- sc->curaid = bss_conf->aid;
- ath9k_hw_write_associd(sc);
+ common->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(ah);
/*
* Request a re-configuration of Beacon related timers
@@ -949,8 +1025,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
ath_start_ani(sc);
} else {
- DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
- sc->curaid = 0;
+ ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
+ common->curaid = 0;
/* Stop ANI */
del_timer_sync(&sc->ani.timer);
}
@@ -1042,8 +1118,8 @@ static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
if (ret)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to register led:%s", led->name);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Failed to register led:%s", led->name);
else
led->registered = 1;
return ret;
@@ -1127,6 +1203,7 @@ fail:
void ath_radio_enable(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *channel = sc->hw->conf.channel;
int r;
@@ -1139,17 +1216,17 @@ void ath_radio_enable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, false);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset channel %u (%uMhz) ",
- "reset status %d\n",
- channel->center_freq, r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset channel %u (%uMhz) ",
+ "reset status %d\n",
+ channel->center_freq, r);
}
spin_unlock_bh(&sc->sc_resetlock);
ath_update_txpow(sc);
if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to restart recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to restart recv logic\n");
return;
}
@@ -1194,17 +1271,17 @@ void ath_radio_disable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, false);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset channel %u (%uMhz) "
- "reset status %d\n",
- channel->center_freq, r);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unable to reset channel %u (%uMhz) "
+ "reset status %d\n",
+ channel->center_freq, r);
}
spin_unlock_bh(&sc->sc_resetlock);
ath9k_hw_phy_disable(ah);
ath9k_hw_configpcipowersave(ah, 1, 1);
ath9k_ps_restore(sc);
- ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+ ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
}
/*******************/
@@ -1236,23 +1313,26 @@ static void ath_start_rfkill_poll(struct ath_softc *sc)
wiphy_rfkill_start_polling(sc->hw->wiphy);
}
-void ath_cleanup(struct ath_softc *sc)
+static void ath9k_uninit_hw(struct ath_softc *sc)
{
- ath_detach(sc);
- free_irq(sc->irq, sc);
- ath_bus_cleanup(sc);
- kfree(sc->sec_wiphy);
- ieee80211_free_hw(sc->hw);
+ struct ath_hw *ah = sc->sc_ah;
+
+ BUG_ON(!ah);
+
+ ath9k_exit_debug(ah);
+ ath9k_hw_detach(ah);
+ sc->sc_ah = NULL;
}
-void ath_detach(struct ath_softc *sc)
+static void ath_clean_core(struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
+ struct ath_hw *ah = sc->sc_ah;
int i = 0;
ath9k_ps_wakeup(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
+ dev_dbg(sc->dev, "Detach ATH hw\n");
ath_deinit_leds(sc);
wiphy_rfkill_stop_polling(sc->hw->wiphy);
@@ -1273,20 +1353,36 @@ void ath_detach(struct ath_softc *sc)
tasklet_kill(&sc->bcon_tasklet);
if (!(sc->sc_flags & SC_OP_INVALID))
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+ ath9k_setpower(sc, ATH9K_PM_AWAKE);
/* cleanup tx queues */
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
- if ((sc->btcoex_info.no_stomp_timer) &&
- sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
- ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer);
+ if ((sc->btcoex.no_stomp_timer) &&
+ ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer);
+}
- ath9k_hw_detach(sc->sc_ah);
- sc->sc_ah = NULL;
- ath9k_exit_debug(sc);
+void ath_detach(struct ath_softc *sc)
+{
+ ath_clean_core(sc);
+ ath9k_uninit_hw(sc);
+}
+
+void ath_cleanup(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ath_clean_core(sc);
+ free_irq(sc->irq, sc);
+ ath_bus_cleanup(common);
+ kfree(sc->sec_wiphy);
+ ieee80211_free_hw(sc->hw);
+
+ ath9k_uninit_hw(sc);
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
@@ -1295,29 +1391,245 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ath_regulatory *reg = &sc->common.regulatory;
+ struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
return ath_reg_notifier_apply(wiphy, request, reg);
}
/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
+ btcoex->bt_priority_cnt++;
+
+ if (time_after(jiffies, btcoex->bt_priority_time +
+ msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
+ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+ "BT priority traffic detected");
+ sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+ } else {
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+ }
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ }
+}
+
+/*
+ * Configures appropriate weight based on stomp type.
+ */
+static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
+ enum ath_stomp_type stomp_type)
+{
+ struct ath_hw *ah = sc->sc_ah;
+
+ switch (stomp_type) {
+ case ATH_BTCOEX_STOMP_ALL:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_ALL_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_LOW:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_NONE:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_NONE_WLAN_WGHT);
+ break;
+ default:
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Invalid Stomptype\n");
+ break;
+ }
+
+ ath9k_hw_btcoex_enable(ah);
+}
+
+static void ath9k_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next,
+ u32 timer_period)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+ ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
+
+ if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ sc->imask |= ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, sc->imask);
+ }
+}
+
+static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+ ath9k_hw_gen_timer_stop(ah, timer);
+
+ /* if no timer is enabled, turn off interrupt mask */
+ if (timer_table->timer_mask.val == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ sc->imask &= ~ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, sc->imask);
+ }
+}
+
+/*
+ * This is the master bt coex timer which runs for every
+ * 45ms, bt traffic will be given priority during 55% of this
+ * period while wlan gets remaining 45%
+ */
+static void ath_btcoex_period_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *) data;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_btcoex *btcoex = &sc->btcoex;
+
+ ath_detect_bt_priority(sc);
+
+ spin_lock_bh(&btcoex->btcoex_lock);
+
+ ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
+
+ spin_unlock_bh(&btcoex->btcoex_lock);
+
+ if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+ ath9k_gen_timer_start(ah,
+ btcoex->no_stomp_timer,
+ (ath9k_hw_gettsf32(ah) +
+ btcoex->btcoex_no_stomp),
+ btcoex->btcoex_no_stomp * 10);
+ btcoex->hw_timer_enabled = true;
+ }
+
+ mod_timer(&btcoex->period_timer, jiffies +
+ msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+}
+
+/*
+ * Generic tsf based hw timer which configures weight
+ * registers to time slice between wlan and bt traffic
+ */
+static void ath_btcoex_no_stomp_timer(void *arg)
+{
+ struct ath_softc *sc = (struct ath_softc *)arg;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_btcoex *btcoex = &sc->btcoex;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "no stomp timer running \n");
+
+ spin_lock_bh(&btcoex->btcoex_lock);
+
+ if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
+ ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
+ else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+ ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
+
+ spin_unlock_bh(&btcoex->btcoex_lock);
+}
+
+static int ath_init_btcoex_timer(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+
+ btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+ btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+ btcoex->btcoex_period / 100;
+
+ setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
+ (unsigned long) sc);
+
+ spin_lock_init(&btcoex->btcoex_lock);
+
+ btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
+ ath_btcoex_no_stomp_timer,
+ ath_btcoex_no_stomp_timer,
+ (void *) sc, AR_FIRST_NDP_TIMER);
+
+ if (!btcoex->no_stomp_timer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/*
+ * Read and write, they both share the same lock. We do this to serialize
+ * reads and writes on Atheros 802.11n PCI devices only. This is required
+ * as the FIFO on these devices can only accept sanely 2 requests. After
+ * that the device goes bananas. Serializing the reads/writes prevents this
+ * from happening.
+ */
+
+static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+{
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+ unsigned long flags;
+ spin_lock_irqsave(&sc->sc_serial_rw, flags);
+ iowrite32(val, sc->mem + reg_offset);
+ spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+ } else
+ iowrite32(val, sc->mem + reg_offset);
+}
+
+static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
+{
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ u32 val;
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+ unsigned long flags;
+ spin_lock_irqsave(&sc->sc_serial_rw, flags);
+ val = ioread32(sc->mem + reg_offset);
+ spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+ } else
+ val = ioread32(sc->mem + reg_offset);
+ return val;
+}
+
+static const struct ath_ops ath9k_common_ops = {
+ .read = ath9k_ioread32,
+ .write = ath9k_iowrite32,
+};
+
+/*
* Initialize and fill ath_softc, ath_sofct is the
* "Software Carrier" struct. Historically it has existed
* to allow the separation between hardware specific
* variables (now in ath_hw) and driver specific variables.
*/
-static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
+static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops)
{
struct ath_hw *ah = NULL;
+ struct ath_common *common;
int r = 0, i;
int csz = 0;
+ int qnum;
/* XXX: hardware will not be ready until ath_open() being called */
sc->sc_flags |= SC_OP_INVALID;
- if (ath9k_init_debug(sc) < 0)
- printk(KERN_ERR "Unable to create debugfs files\n");
-
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
@@ -1328,39 +1640,50 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
(unsigned long)sc);
- /*
- * Cache line size is used to size and align various
- * structures used to communicate with the hardware.
- */
- ath_read_cachesize(sc, &csz);
- /* XXX assert csz is non-zero */
- sc->common.cachelsz = csz << 2; /* convert to bytes */
-
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
- if (!ah) {
- r = -ENOMEM;
- goto bad_no_ah;
- }
+ if (!ah)
+ return -ENOMEM;
- ah->ah_sc = sc;
ah->hw_version.devid = devid;
ah->hw_version.subsysid = subsysid;
sc->sc_ah = ah;
+ common = ath9k_hw_common(ah);
+ common->ops = &ath9k_common_ops;
+ common->bus_ops = bus_ops;
+ common->ah = ah;
+ common->hw = sc->hw;
+ common->priv = sc;
+ common->debug_mask = ath9k_debug;
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ ath_read_cachesize(common, &csz);
+ /* XXX assert csz is non-zero */
+ common->cachelsz = csz << 2; /* convert to bytes */
+
r = ath9k_hw_init(ah);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to initialize hardware; "
- "initialization status: %d\n", r);
- goto bad;
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to initialize hardware; "
+ "initialization status: %d\n", r);
+ goto bad_free_hw;
+ }
+
+ if (ath9k_init_debug(ah) < 0) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to create debugfs files\n");
+ goto bad_free_hw;
}
/* Get the hardware key cache size. */
sc->keymax = ah->caps.keycache_size;
if (sc->keymax > ATH_KEYMAX) {
- DPRINTF(sc, ATH_DBG_ANY,
- "Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, sc->keymax);
+ ath_print(common, ATH_DBG_ANY,
+ "Warning, using only %u entries in %u key cache\n",
+ ATH_KEYMAX, sc->keymax);
sc->keymax = ATH_KEYMAX;
}
@@ -1386,17 +1709,17 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
* priority. Note that the hal handles reseting
* these queues at the needed time.
*/
- sc->beacon.beaconq = ath_beaconq_setup(ah);
+ sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah);
if (sc->beacon.beaconq == -1) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup a beacon xmit queue\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup a beacon xmit queue\n");
r = -EIO;
goto bad2;
}
sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
if (sc->beacon.cabq == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup CAB xmit queue\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup CAB xmit queue\n");
r = -EIO;
goto bad2;
}
@@ -1410,27 +1733,27 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
/* Setup data queues */
/* NB: ensure BK queue is the lowest priority h/w queue */
if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BK traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BK traffic\n");
r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BE traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BE traffic\n");
r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VI traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VI traffic\n");
r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VO traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VO traffic\n");
r = -EIO;
goto bad2;
}
@@ -1480,14 +1803,14 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
sc->sc_flags |= SC_OP_RXAGGR;
}
- sc->tx_chainmask = ah->caps.tx_chainmask;
- sc->rx_chainmask = ah->caps.rx_chainmask;
+ common->tx_chainmask = ah->caps.tx_chainmask;
+ common->rx_chainmask = ah->caps.rx_chainmask;
ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
sc->rx.defant = ath9k_hw_getdefantenna(ah);
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
+ memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
@@ -1515,10 +1838,24 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
ARRAY_SIZE(ath9k_5ghz_chantable);
}
- if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) {
- r = ath9k_hw_btcoex_init(ah);
+ switch (ah->btcoex_hw.scheme) {
+ case ATH_BTCOEX_CFG_NONE:
+ break;
+ case ATH_BTCOEX_CFG_2WIRE:
+ ath9k_hw_btcoex_init_2wire(ah);
+ break;
+ case ATH_BTCOEX_CFG_3WIRE:
+ ath9k_hw_btcoex_init_3wire(ah);
+ r = ath_init_btcoex_timer(sc);
if (r)
goto bad2;
+ qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+ ath9k_hw_init_btcoex_hw(ah, qnum);
+ sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+ break;
+ default:
+ WARN_ON(1);
+ break;
}
return 0;
@@ -1527,12 +1864,9 @@ bad2:
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-bad:
- ath9k_hw_detach(ah);
- sc->sc_ah = NULL;
-bad_no_ah:
- ath9k_exit_debug(sc);
+bad_free_hw:
+ ath9k_uninit_hw(sc);
return r;
}
@@ -1574,34 +1908,40 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
}
/* Device driver core initialization */
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid)
+int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops)
{
struct ieee80211_hw *hw = sc->hw;
+ struct ath_common *common;
+ struct ath_hw *ah;
int error = 0, i;
struct ath_regulatory *reg;
- DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
+ dev_dbg(sc->dev, "Attach ATH hw\n");
- error = ath_init_softc(devid, sc, subsysid);
+ error = ath_init_softc(devid, sc, subsysid, bus_ops);
if (error != 0)
return error;
+ ah = sc->sc_ah;
+ common = ath9k_hw_common(ah);
+
/* get mac address from hardware and set in mac80211 */
- SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
+ SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
ath_set_hw_capab(sc, hw);
- error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy,
+ error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
return error;
- reg = &sc->common.regulatory;
+ reg = &common->regulatory;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+ if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes))
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
@@ -1639,9 +1979,7 @@ error_attach:
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
- ath9k_hw_detach(sc->sc_ah);
- sc->sc_ah = NULL;
- ath9k_exit_debug(sc);
+ ath9k_uninit_hw(sc);
return error;
}
@@ -1649,6 +1987,7 @@ error_attach:
int ath_reset(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hw *hw = sc->hw;
int r;
@@ -1660,12 +1999,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
if (r)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n", r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d\n", r);
spin_unlock_bh(&sc->sc_resetlock);
if (ath_startrecv(sc) != 0)
- DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to start recv logic\n");
/*
* We may be doing a reset in response to a request
@@ -1708,19 +2048,20 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
-
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_desc *ds;
struct ath_buf *bf;
int i, bsize, error;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
- name, nbuf, ndesc);
+ ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
+ name, nbuf, ndesc);
INIT_LIST_HEAD(head);
/* ath_desc must be a multiple of DWORDs */
if ((sizeof(struct ath_desc) % 4) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n");
- ASSERT((sizeof(struct ath_desc) % 4) == 0);
+ ath_print(common, ATH_DBG_FATAL,
+ "ath_desc not DWORD aligned\n");
+ BUG_ON((sizeof(struct ath_desc) % 4) != 0);
error = -ENOMEM;
goto fail;
}
@@ -1753,9 +2094,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
goto fail;
}
ds = dd->dd_desc;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
- name, ds, (u32) dd->dd_desc_len,
- ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+ ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
+ name, ds, (u32) dd->dd_desc_len,
+ ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
/* allocate buffers */
bsize = sizeof(struct ath_buf) * nbuf;
@@ -1778,7 +2119,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
* descriptor fetch.
*/
while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
- ASSERT((caddr_t) bf->bf_desc <
+ BUG_ON((caddr_t) bf->bf_desc >=
((caddr_t) dd->dd_desc +
dd->dd_desc_len));
@@ -1882,31 +2223,50 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
}
- sc->tx_chan_width = ATH9K_HT_MACMODE_20;
-
- if (conf_is_ht(conf)) {
- if (conf_is_ht40(conf))
- sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
-
+ if (conf_is_ht(conf))
ichan->chanmode = ath_get_extchanmode(sc, chan,
conf->channel_type);
- }
}
/**********************/
/* mac80211 callbacks */
/**********************/
+/*
+ * (Re)start btcoex timers
+ */
+static void ath9k_btcoex_timer_resume(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Starting btcoex timers");
+
+ /* make sure duty cycle timer is also stopped when resuming */
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+
+ mod_timer(&btcoex->period_timer, jiffies);
+}
+
static int ath9k_start(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *curchan = hw->conf.channel;
struct ath9k_channel *init_channel;
int r;
- DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with "
- "initial channel: %d MHz\n", curchan->center_freq);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Starting driver with initial channel: %d MHz\n",
+ curchan->center_freq);
mutex_lock(&sc->mutex);
@@ -1938,7 +2298,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
init_channel = ath_get_curchannel(sc, hw);
/* Reset SERDES registers */
- ath9k_hw_configpcipowersave(sc->sc_ah, 0, 0);
+ ath9k_hw_configpcipowersave(ah, 0, 0);
/*
* The basic interface to setting the hardware in a good
@@ -1948,12 +2308,12 @@ static int ath9k_start(struct ieee80211_hw *hw)
* and then setup of the interrupt mask.
*/
spin_lock_bh(&sc->sc_resetlock);
- r = ath9k_hw_reset(sc->sc_ah, init_channel, false);
+ r = ath9k_hw_reset(ah, init_channel, false);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d "
- "(freq %u MHz)\n", r,
- curchan->center_freq);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d "
+ "(freq %u MHz)\n", r,
+ curchan->center_freq);
spin_unlock_bh(&sc->sc_resetlock);
goto mutex_unlock;
}
@@ -1973,7 +2333,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
* here except setup the interrupt mask.
*/
if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to start recv logic\n");
r = -EIO;
goto mutex_unlock;
}
@@ -1983,10 +2344,10 @@ static int ath9k_start(struct ieee80211_hw *hw)
| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
| ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
sc->imask |= ATH9K_INT_GTT;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
sc->imask |= ATH9K_INT_CST;
ath_cache_conf_rate(sc, &hw->conf);
@@ -1995,21 +2356,22 @@ static int ath9k_start(struct ieee80211_hw *hw)
/* Disable BMISS interrupt when we're not associated */
sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
- ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+ ath9k_hw_set_interrupts(ah, sc->imask);
ieee80211_wake_queues(hw);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
- if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) &&
- !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) {
- ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT,
- AR_STOMP_LOW_WLAN_WGHT);
- ath9k_hw_btcoex_enable(sc->sc_ah);
+ if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
+ !ah->btcoex_hw.enabled) {
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ ath9k_hw_btcoex_enable(ah);
- ath_pcie_aspm_disable(sc);
- if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
- ath_btcoex_timer_resume(sc, &sc->btcoex_info);
+ if (common->bus_ops->bt_coex_prep)
+ common->bus_ops->bt_coex_prep(common);
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath9k_btcoex_timer_resume(sc);
}
mutex_unlock:
@@ -2024,12 +2386,14 @@ static int ath9k_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_tx_control txctl;
int hdrlen, padsize;
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
- printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state "
- "%d\n", wiphy_name(hw->wiphy), aphy->state);
+ ath_print(common, ATH_DBG_XMIT,
+ "ath9k: %s: TX in unexpected wiphy state "
+ "%d\n", wiphy_name(hw->wiphy), aphy->state);
goto exit;
}
@@ -2042,8 +2406,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (ieee80211_is_data(hdr->frame_control) &&
!ieee80211_is_nullfunc(hdr->frame_control) &&
!ieee80211_has_pm(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "Add PM=1 for a TX frame "
- "while in PS mode\n");
+ ath_print(common, ATH_DBG_PS, "Add PM=1 for a TX frame "
+ "while in PS mode\n");
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
}
}
@@ -2058,11 +2422,12 @@ static int ath9k_tx(struct ieee80211_hw *hw,
ath9k_ps_wakeup(sc);
ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a "
- "buffered frame\n");
+ ath_print(common, ATH_DBG_PS,
+ "Sending PS-Poll to pick a buffered frame\n");
sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA;
} else {
- DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n");
+ ath_print(common, ATH_DBG_PS,
+ "Wake up to complete TX\n");
sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK;
}
/*
@@ -2104,10 +2469,10 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (!txctl.txq)
goto exit;
- DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
if (ath_tx_start(hw, skb, &txctl) != 0) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n");
+ ath_print(common, ATH_DBG_XMIT, "TX failed\n");
goto exit;
}
@@ -2117,10 +2482,28 @@ exit:
return 0;
}
+/*
+ * Pause btcoex timer and bt duty cycle timer
+ */
+static void ath9k_btcoex_timer_pause(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ del_timer_sync(&btcoex->period_timer);
+
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+ btcoex->hw_timer_enabled = false;
+}
+
static void ath9k_stop(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
mutex_lock(&sc->mutex);
@@ -2135,7 +2518,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
}
if (sc->sc_flags & SC_OP_INVALID) {
- DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+ ath_print(common, ATH_DBG_ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
return;
}
@@ -2145,33 +2528,33 @@ static void ath9k_stop(struct ieee80211_hw *hw)
return; /* another wiphy still in use */
}
- if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) {
- ath9k_hw_btcoex_disable(sc->sc_ah);
- if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
- ath_btcoex_timer_pause(sc, &sc->btcoex_info);
+ if (ah->btcoex_hw.enabled) {
+ ath9k_hw_btcoex_disable(ah);
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath9k_btcoex_timer_pause(sc);
}
/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
- ath9k_hw_set_interrupts(sc->sc_ah, 0);
+ ath9k_hw_set_interrupts(ah, 0);
if (!(sc->sc_flags & SC_OP_INVALID)) {
ath_drain_all_txq(sc, false);
ath_stoprecv(sc);
- ath9k_hw_phy_disable(sc->sc_ah);
+ ath9k_hw_phy_disable(ah);
} else
sc->rx.rxlink = NULL;
/* disable HAL and put h/w to sleep */
- ath9k_hw_disable(sc->sc_ah);
- ath9k_hw_configpcipowersave(sc->sc_ah, 1, 1);
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
+ ath9k_hw_disable(ah);
+ ath9k_hw_configpcipowersave(ah, 1, 1);
+ ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
sc->sc_flags |= SC_OP_INVALID;
mutex_unlock(&sc->mutex);
- DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n");
+ ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
}
static int ath9k_add_interface(struct ieee80211_hw *hw,
@@ -2179,6 +2562,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)conf->vif->drv_priv;
enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
int ret = 0;
@@ -2205,13 +2589,14 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ic_opmode = conf->type;
break;
default:
- DPRINTF(sc, ATH_DBG_FATAL,
+ ath_print(common, ATH_DBG_FATAL,
"Interface type %d not yet supported\n", conf->type);
ret = -EOPNOTSUPP;
goto out;
}
- DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Attach a VIF of type: %d\n", ic_opmode);
/* Set the VIF opmode */
avp->av_opmode = ic_opmode;
@@ -2261,10 +2646,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)conf->vif->drv_priv;
int i;
- DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
+ ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
mutex_lock(&sc->mutex);
@@ -2299,6 +2685,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
bool all_wiphys_idle = false, disable_radio = false;
@@ -2318,8 +2705,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
else if (all_wiphys_idle) {
ath_radio_enable(sc);
- DPRINTF(sc, ATH_DBG_CONFIG,
- "not-idle: enabling radio\n");
+ ath_print(common, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
}
}
@@ -2337,7 +2724,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
sc->ps_enabled = true;
} else {
sc->ps_enabled = false;
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+ ath9k_setpower(sc, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
ath9k_hw_setrxabort(sc->sc_ah, 0);
@@ -2372,8 +2759,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
goto skip_chan_change;
}
- DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
- curchan->center_freq);
+ ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+ curchan->center_freq);
/* XXX: remove me eventualy */
ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
@@ -2381,7 +2768,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
ath_update_chainmask(sc, conf_is_ht(conf));
if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to set channel\n");
mutex_unlock(&sc->mutex);
return -EINVAL;
}
@@ -2392,7 +2780,7 @@ skip_chan_change:
sc->config.txpowlimit = 2 * conf->power_level;
if (disable_radio) {
- DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
ath_radio_disable(sc);
}
@@ -2429,7 +2817,8 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
ath9k_ps_restore(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Set HW RX filter: 0x%x\n", rfilt);
}
static void ath9k_sta_notify(struct ieee80211_hw *hw,
@@ -2457,6 +2846,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_tx_queue_info qi;
int ret = 0, qnum;
@@ -2473,15 +2863,15 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
qi.tqi_burstTime = params->txop;
qnum = ath_get_hal_qnum(queue, sc);
- DPRINTF(sc, ATH_DBG_CONFIG,
- "Configure tx [queue/halq] [%d/%d], "
- "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
- queue, qnum, params->aifs, params->cw_min,
- params->cw_max, params->txop);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Configure tx [queue/halq] [%d/%d], "
+ "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ queue, qnum, params->aifs, params->cw_min,
+ params->cw_max, params->txop);
ret = ath_txq_update(sc, qnum, &qi);
if (ret)
- DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n");
+ ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
mutex_unlock(&sc->mutex);
@@ -2496,6 +2886,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
if (modparam_nohwcrypt)
@@ -2503,7 +2894,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n");
+ ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
switch (cmd) {
case SET_KEY:
@@ -2540,6 +2931,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
u32 rfilt = 0;
int error, i;
@@ -2555,9 +2947,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ah->opmode != NL80211_IFTYPE_AP) {
ah->opmode = NL80211_IFTYPE_STATION;
ath9k_hw_setopmode(ah);
- memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN);
- sc->curaid = 0;
- ath9k_hw_write_associd(sc);
+ memcpy(common->curbssid, common->macaddr, ETH_ALEN);
+ common->curaid = 0;
+ ath9k_hw_write_associd(ah);
/* Request full reset to get hw opmode changed properly */
sc->sc_flags |= SC_OP_FULL_RESET;
}
@@ -2569,17 +2961,17 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
/* Set BSSID */
- memcpy(sc->curbssid, bss_conf->bssid, ETH_ALEN);
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
- sc->curaid = 0;
- ath9k_hw_write_associd(sc);
+ common->curaid = 0;
+ ath9k_hw_write_associd(ah);
/* Set aggregation protection mode parameters */
sc->config.ath_aggr_prot = 0;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "RX filter 0x%x bssid %pM aid 0x%x\n",
- rfilt, sc->curbssid, sc->curaid);
+ ath_print(common, ATH_DBG_CONFIG,
+ "RX filter 0x%x bssid %pM aid 0x%x\n",
+ rfilt, common->curbssid, common->curaid);
/* need to reconfigure the beacon */
sc->sc_flags &= ~SC_OP_BEACONS ;
@@ -2618,7 +3010,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
ath9k_hw_keysetmac(sc->sc_ah,
(u16)i,
- sc->curbssid);
+ common->curbssid);
}
/* Only legacy IBSS for now */
@@ -2626,8 +3018,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath_update_chainmask(sc, 0);
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
- bss_conf->use_short_preamble);
+ ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
+ bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
else
@@ -2635,8 +3027,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
- bss_conf->use_cts_prot);
+ ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
+ bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot &&
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
sc->sc_flags |= SC_OP_PROTECT_ENABLE;
@@ -2645,7 +3037,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ASSOC) {
- DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+ ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
bss_conf->assoc);
ath9k_bss_assoc_info(sc, vif, bss_conf);
}
@@ -2694,7 +3086,11 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw)
struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex);
+
+ ath9k_ps_wakeup(sc);
ath9k_hw_reset_tsf(sc->sc_ah);
+ ath9k_ps_restore(sc);
+
mutex_unlock(&sc->mutex);
}
@@ -2726,7 +3122,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath_tx_aggr_resume(sc, sta, tid);
break;
default:
- DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unknown AMPDU action\n");
}
return ret;
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 903dd8ad9d4..63059b6a90d 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -31,8 +31,9 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
};
/* return bus cachesize in 4B word units */
-static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
+static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
u8 u8tmp;
pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp);
@@ -48,8 +49,9 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
*csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
}
-static void ath_pci_cleanup(struct ath_softc *sc)
+static void ath_pci_cleanup(struct ath_common *common)
{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
struct pci_dev *pdev = to_pci_dev(sc->dev);
pci_iounmap(pdev, sc->mem);
@@ -57,9 +59,11 @@ static void ath_pci_cleanup(struct ath_softc *sc)
pci_release_region(pdev, 0);
}
-static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
+static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
- (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+ struct ath_hw *ah = (struct ath_hw *) common->ah;
+
+ common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
if (!ath9k_hw_wait(ah,
AR_EEPROM_STATUS_DATA,
@@ -69,16 +73,34 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
return false;
}
- *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+ *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
AR_EEPROM_STATUS_DATA_VAL);
return true;
}
-static struct ath_bus_ops ath_pci_bus_ops = {
+/*
+ * Bluetooth coexistance requires disabling ASPM.
+ */
+static void ath_pci_bt_coex_prep(struct ath_common *common)
+{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct pci_dev *pdev = to_pci_dev(sc->dev);
+ u8 aspm;
+
+ if (!pdev->is_pcie)
+ return;
+
+ pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
+ aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1);
+ pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
+}
+
+const static struct ath_bus_ops ath_pci_bus_ops = {
.read_cachesize = ath_pci_read_cachesize,
.cleanup = ath_pci_cleanup,
.eeprom_read = ath_pci_eeprom_read,
+ .bt_coex_prep = ath_pci_bt_coex_prep,
};
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -177,10 +199,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->hw = hw;
sc->dev = &pdev->dev;
sc->mem = mem;
- sc->bus_ops = &ath_pci_bus_ops;
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
- ret = ath_init_device(id->device, sc, subsysid);
+ ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto bad3;
diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c
index 63bf9a307c6..72a17c43a5a 100644
--- a/drivers/net/wireless/ath/ath9k/phy.c
+++ b/drivers/net/wireless/ath/ath9k/phy.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
void
ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex,
@@ -26,6 +26,7 @@ ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex,
bool
ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 channelSel = 0;
u32 bModeSynth = 0;
u32 aModeRefSel = 0;
@@ -46,8 +47,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ((freq - 704) * 2 - 3040) / 10;
bModeSynth = 1;
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid channel %u MHz\n", freq);
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid channel %u MHz\n", freq);
return false;
}
@@ -79,8 +80,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid channel %u MHz\n", freq);
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid channel %u MHz\n", freq);
return false;
}
@@ -112,20 +113,31 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
if (freq < 4800) {
u32 txctl;
+ int regWrites = 0;
bMode = 1;
fracMode = 1;
aModeRefSel = 0;
channelSel = (freq * 0x10000) / 15;
- txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
- if (freq == 2484) {
-
- REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
- txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+ if (AR_SREV_9287_11_OR_LATER(ah)) {
+ if (freq == 2484) {
+ REG_WRITE_ARRAY(&ah->iniCckfirJapan2484,
+ 1, regWrites);
+ } else {
+ REG_WRITE_ARRAY(&ah->iniCckfirNormal,
+ 1, regWrites);
+ }
} else {
- REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
- txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+ txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+ if (freq == 2484) {
+ /* Enable channel spreading for channel 14 */
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+ } else {
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
+ }
}
} else {
bMode = 0;
@@ -285,6 +297,8 @@ ath9k_hw_rf_free(struct ath_hw *ah)
bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
if (!AR_SREV_9280_10_OR_LATER(ah)) {
ah->analogBank0Data =
kzalloc((sizeof(u32) *
@@ -315,8 +329,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
|| ah->analogBank6Data == NULL
|| ah->analogBank6TPCData == NULL
|| ah->analogBank7Data == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Cannot allocate RF banks\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Cannot allocate RF banks\n");
*status = -ENOMEM;
return false;
}
@@ -326,8 +340,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
ah->iniAddac.ia_rows *
ah->iniAddac.ia_columns), GFP_KERNEL);
if (ah->addac5416_21 == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Cannot allocate addac5416_21\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Cannot allocate addac5416_21\n");
*status = -ENOMEM;
return false;
}
@@ -336,8 +350,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
kzalloc((sizeof(u32) *
ah->iniBank6.ia_rows), GFP_KERNEL);
if (ah->bank6Temp == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Cannot allocate bank6Temp\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Cannot allocate bank6Temp\n");
*status = -ENOMEM;
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index dfda6f44464..140fef74c66 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -45,6 +45,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_FC_DYN2040_EN 0x00000004
#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008
#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010
+/* For 25 MHz channel spacing -- not used but supported by hw */
#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020
#define AR_PHY_FC_HT_EN 0x00000040
#define AR_PHY_FC_SHORT_GI_40 0x00000080
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 1895d63aad0..bb72b46567f 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -425,7 +425,7 @@ static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
u8 index, int valid_tx_rate)
{
- ASSERT(index <= ath_rc_priv->rate_table_size);
+ BUG_ON(index > ath_rc_priv->rate_table_size);
ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
@@ -1160,6 +1160,7 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
bool is_cw_40)
{
int mode = 0;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
switch(band) {
case IEEE80211_BAND_2GHZ:
@@ -1177,13 +1178,14 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
mode = ATH9K_MODE_11NA_HT40PLUS;
break;
default:
- DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n");
+ ath_print(common, ATH_DBG_CONFIG, "Invalid band\n");
return NULL;
}
BUG_ON(mode >= ATH9K_MODE_MAX);
- DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Choosing rate table for mode: %d\n", mode);
return sc->hw_rate_table[mode];
}
@@ -1194,11 +1196,13 @@ static void ath_rc_init(struct ath_softc *sc,
const struct ath_rate_table *rate_table)
{
struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
u8 i, j, k, hi = 0, hthi = 0;
if (!rate_table) {
- DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Rate table not initialized\n");
return;
}
@@ -1239,7 +1243,7 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->rate_table_size = hi + 1;
ath_rc_priv->rate_max_phy = 0;
- ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
+ BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
@@ -1253,16 +1257,17 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
}
- ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
- ASSERT(k <= RATE_TABLE_SIZE);
+ BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
+ BUG_ON(k > RATE_TABLE_SIZE);
ath_rc_priv->max_valid_rate = k;
ath_rc_sort_validrates(rate_table, ath_rc_priv);
ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
sc->cur_rate_table = rate_table;
- DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n",
- ath_rc_priv->ht_cap);
+ ath_print(common, ATH_DBG_CONFIG,
+ "RC Initialized with capabilities: 0x%x\n",
+ ath_rc_priv->ht_cap);
}
static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -1438,9 +1443,9 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
oper_cw40, oper_sgi40);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
- DPRINTF(sc, ATH_DBG_CONFIG,
- "Operating HT Bandwidth changed to: %d\n",
- sc->hw->conf.channel_type);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Operating HT Bandwidth changed to: %d\n",
+ sc->hw->conf.channel_type);
}
}
}
@@ -1463,8 +1468,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
if (!rate_priv) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to allocate private rc structure\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unable to allocate private rc structure\n");
return NULL;
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index ec0abf82399..c880a55939b 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -59,7 +59,7 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
/* virtual addr of the beginning of the buffer. */
skb = bf->bf_mpdu;
- ASSERT(skb != NULL);
+ BUG_ON(skb == NULL);
ds->ds_vdata = skb->data;
/* setup rx descriptors. The rx.bufsize here tells the harware
@@ -272,6 +272,8 @@ rx_next:
static void ath_opmode_init(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
u32 rfilt, mfilt[2];
/* configure rx filter */
@@ -280,13 +282,13 @@ static void ath_opmode_init(struct ath_softc *sc)
/* configure bssid mask */
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- ath9k_hw_setbssidmask(sc);
+ ath_hw_setbssidmask(common);
/* configure operational mode */
ath9k_hw_setopmode(ah);
/* Handle any link-level address change. */
- ath9k_hw_setmac(ah, sc->sc_ah->macaddr);
+ ath9k_hw_setmac(ah, common->macaddr);
/* calculate and install multicast filter */
mfilt[0] = mfilt[1] = ~0;
@@ -295,6 +297,7 @@ static void ath_opmode_init(struct ath_softc *sc)
int ath_rx_init(struct ath_softc *sc, int nbufs)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct sk_buff *skb;
struct ath_buf *bf;
int error = 0;
@@ -304,23 +307,23 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
spin_lock_init(&sc->rx.rxbuflock);
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
- min(sc->common.cachelsz, (u16)64));
+ min(common->cachelsz, (u16)64));
- DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
- sc->common.cachelsz, sc->rx.bufsize);
+ ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+ common->cachelsz, sc->rx.bufsize);
/* Initialize rx descriptors */
error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
"rx", nbufs, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "failed to allocate rx descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "failed to allocate rx descriptors: %d\n", error);
goto err;
}
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL);
+ skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_KERNEL);
if (skb == NULL) {
error = -ENOMEM;
goto err;
@@ -334,8 +337,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL,
- "dma_mapping_error() on RX init\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error() on RX init\n");
error = -ENOMEM;
goto err;
}
@@ -420,7 +423,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
else
rfilt |= ATH9K_RX_FILTER_BEACON;
- if (sc->rx.rxfilter & FIF_PSPOLL)
+ if ((AR_SREV_9280_10_OR_LATER(sc->sc_ah) ||
+ AR_SREV_9285_10_OR_LATER(sc->sc_ah)) &&
+ (sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (sc->rx.rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
if (conf_is_ht(&sc->hw->conf))
@@ -527,20 +533,22 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
if (skb->len < 24 + 8 + 2 + 2)
return;
mgmt = (struct ieee80211_mgmt *)skb->data;
- if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
+ if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0)
return; /* not from our current AP */
sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
if (sc->sc_flags & SC_OP_BEACON_SYNC) {
sc->sc_flags &= ~SC_OP_BEACON_SYNC;
- DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
- "timestamp from the AP\n");
+ ath_print(common, ATH_DBG_PS,
+ "Reconfigure Beacon timers based on "
+ "timestamp from the AP\n");
ath_beacon_config(sc, NULL);
}
@@ -552,8 +560,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* a backup trigger for returning into NETWORK SLEEP state,
* so we are waiting for it as well.
*/
- DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
- "buffered broadcast/multicast frame(s)\n");
+ ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating "
+ "buffered broadcast/multicast frame(s)\n");
sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON;
return;
}
@@ -565,13 +573,15 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* been delivered.
*/
sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
- DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
+ ath_print(common, ATH_DBG_PS,
+ "PS wait for CAB frames timed out\n");
}
}
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -589,14 +599,15 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
* point.
*/
sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
- DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
- "sleep\n");
+ ath_print(common, ATH_DBG_PS,
+ "All PS CAB frames received, back to sleep\n");
} else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
!is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_morefrags(hdr->frame_control)) {
sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
- DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
- "received PS-Poll data (0x%x)\n",
+ ath_print(common, ATH_DBG_PS,
+ "Going back to sleep after having received "
+ "PS-Poll data (0x%x)\n",
sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
@@ -651,6 +662,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct sk_buff *skb = NULL, *requeue_skb;
struct ieee80211_rx_status rx_status;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr;
int hdrlen, padsize, retval;
bool decrypt_error = false;
@@ -749,7 +761,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
/* Ensure we always have an skb to requeue once we are done
* processing the current buffer's skb */
- requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC);
+ requeue_skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_ATOMIC);
/* If there is no memory we ignore the current RX'd frame,
* tell hardware it can give us a new frame using the old
@@ -811,8 +823,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
bf->bf_buf_addr))) {
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL,
- "dma_mapping_error() on RX\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error() on RX\n");
ath_rx_send_to_mac80211(sc, skb, &rx_status);
break;
}
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index d83b77f821e..ceed0095efa 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -17,6 +17,8 @@
#ifndef REG_H
#define REG_H
+#include "../reg.h"
+
#define AR_CR 0x0008
#define AR_CR_RXE 0x00000004
#define AR_CR_RXD 0x00000020
@@ -1421,9 +1423,6 @@ enum {
#define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000
#define AR_SLEEP2_BEACON_TIMEOUT_S 21
-#define AR_BSSMSKL 0x80e0
-#define AR_BSSMSKU 0x80e4
-
#define AR_TPC 0x80e8
#define AR_TPC_ACK 0x0000003f
#define AR_TPC_ACK_S 0x00
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 19b88f8177f..bc7d173b6fa 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -40,6 +40,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_vif_iter_data iter_data;
int i, j;
u8 mask[ETH_ALEN];
@@ -51,7 +52,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
*/
iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
if (iter_data.addr) {
- memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN);
+ memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
iter_data.count = 1;
} else
iter_data.count = 0;
@@ -86,20 +87,21 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
kfree(iter_data.addr);
/* Invert the mask and configure hardware */
- sc->bssidmask[0] = ~mask[0];
- sc->bssidmask[1] = ~mask[1];
- sc->bssidmask[2] = ~mask[2];
- sc->bssidmask[3] = ~mask[3];
- sc->bssidmask[4] = ~mask[4];
- sc->bssidmask[5] = ~mask[5];
-
- ath9k_hw_setbssidmask(sc);
+ common->bssidmask[0] = ~mask[0];
+ common->bssidmask[1] = ~mask[1];
+ common->bssidmask[2] = ~mask[2];
+ common->bssidmask[3] = ~mask[3];
+ common->bssidmask[4] = ~mask[4];
+ common->bssidmask[5] = ~mask[5];
+
+ ath_hw_setbssidmask(common);
}
int ath9k_wiphy_add(struct ath_softc *sc)
{
int i, error;
struct ath_wiphy *aphy;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hw *hw;
u8 addr[ETH_ALEN];
@@ -138,7 +140,7 @@ int ath9k_wiphy_add(struct ath_softc *sc)
sc->sec_wiphy[i] = aphy;
spin_unlock_bh(&sc->wiphy_lock);
- memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN);
+ memcpy(addr, common->macaddr, ETH_ALEN);
addr[0] |= 0x02; /* Locally managed address */
/*
* XOR virtual wiphy index into the least significant bits to generate
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 42551a48c8a..2a4efcbced6 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -107,7 +107,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
- ASSERT(tid->paused > 0);
+ BUG_ON(tid->paused <= 0);
spin_lock_bh(&txq->axq_lock);
tid->paused--;
@@ -131,7 +131,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
struct list_head bf_head;
INIT_LIST_HEAD(&bf_head);
- ASSERT(tid->paused > 0);
+ BUG_ON(tid->paused <= 0);
spin_lock_bh(&txq->axq_lock);
tid->paused--;
@@ -143,7 +143,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
while (!list_empty(&tid->buf_q)) {
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
- ASSERT(!bf_isretried(bf));
+ BUG_ON(bf_isretried(bf));
list_move_tail(&bf->list, &bf_head);
ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
}
@@ -178,7 +178,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
- ASSERT(tid->tx_buf[cindex] == NULL);
+ BUG_ON(tid->tx_buf[cindex] != NULL);
tid->tx_buf[cindex] = bf;
if (index >= ((tid->baw_tail - tid->baw_head) &
@@ -358,7 +358,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
else
INIT_LIST_HEAD(&bf_head);
} else {
- ASSERT(!list_empty(bf_q));
+ BUG_ON(list_empty(bf_q));
list_move_tail(&bf->list, &bf_head);
}
@@ -815,6 +815,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
int qnum;
@@ -854,9 +855,9 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
return NULL;
}
if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "qnum %u out of range, max %u!\n",
- qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
+ ath_print(common, ATH_DBG_FATAL,
+ "qnum %u out of range, max %u!\n",
+ qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
ath9k_hw_releasetxqueue(ah, qnum);
return NULL;
}
@@ -884,9 +885,9 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
switch (qtype) {
case ATH9K_TX_QUEUE_DATA:
if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
- haltype, ARRAY_SIZE(sc->tx.hwq_map));
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "HAL AC %u out of range, max %zu!\n",
+ haltype, ARRAY_SIZE(sc->tx.hwq_map));
return -1;
}
qnum = sc->tx.hwq_map[haltype];
@@ -914,9 +915,9 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
spin_lock_bh(&txq->axq_lock);
if (txq->axq_depth >= (ATH_TXBUF - 20)) {
- DPRINTF(sc, ATH_DBG_XMIT,
- "TX queue: %d is full, depth: %d\n",
- qnum, txq->axq_depth);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
+ "TX queue: %d is full, depth: %d\n",
+ qnum, txq->axq_depth);
ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
txq->stopped = 1;
spin_unlock_bh(&txq->axq_lock);
@@ -945,7 +946,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
return 0;
}
- ASSERT(sc->tx.txq[qnum].axq_qnum == qnum);
+ BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
ath9k_hw_get_txq_props(ah, qnum, &qi);
qi.tqi_aifs = qinfo->tqi_aifs;
@@ -955,8 +956,8 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
qi.tqi_readyTime = qinfo->tqi_readyTime;
if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to update hardware queue %u!\n", qnum);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unable to update hardware queue %u!\n", qnum);
error = -EIO;
} else {
ath9k_hw_resettxqueue(ah, qnum);
@@ -1055,6 +1056,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_txq *txq;
int i, npend = 0;
@@ -1076,14 +1078,15 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
if (npend) {
int r;
- DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
+ ath_print(common, ATH_DBG_XMIT,
+ "Unable to stop TxDMA. Reset HAL!\n");
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
if (r)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n",
- r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d\n",
+ r);
spin_unlock_bh(&sc->sc_resetlock);
}
@@ -1147,8 +1150,8 @@ int ath_tx_setup(struct ath_softc *sc, int haltype)
struct ath_txq *txq;
if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "HAL AC %u out of range, max %zu!\n",
haltype, ARRAY_SIZE(sc->tx.hwq_map));
return 0;
}
@@ -1172,6 +1175,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *head)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf;
/*
@@ -1188,19 +1192,19 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
txq->axq_depth++;
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
- DPRINTF(sc, ATH_DBG_QUEUE,
- "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
+ ath_print(common, ATH_DBG_QUEUE,
+ "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
if (txq->axq_link == NULL) {
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- DPRINTF(sc, ATH_DBG_XMIT,
- "TXDP[%u] = %llx (%p)\n",
- txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
+ ath_print(common, ATH_DBG_XMIT,
+ "TXDP[%u] = %llx (%p)\n",
+ txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
} else {
*txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
- txq->axq_qnum, txq->axq_link,
- ito64(bf->bf_daddr), bf->bf_desc);
+ ath_print(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
+ txq->axq_qnum, txq->axq_link,
+ ito64(bf->bf_daddr), bf->bf_desc);
}
txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
ath9k_hw_txstart(ah, txq->axq_qnum);
@@ -1452,6 +1456,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
const struct ath_rate_table *rt = sc->cur_rate_table;
struct ath9k_11n_rate_series series[4];
struct sk_buff *skb;
@@ -1507,7 +1512,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
rix = rates[i].idx;
series[i].Tries = rates[i].count;
- series[i].ChSel = sc->tx_chainmask;
+ series[i].ChSel = common->tx_chainmask;
if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
series[i].Rate = rt->info[rix].ratecode |
@@ -1587,7 +1592,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_mpdu = NULL;
kfree(tx_info_priv);
tx_info->rate_driver_data[0] = NULL;
- DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "dma_mapping_error() on TX\n");
return -ENOMEM;
}
@@ -1669,12 +1675,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_buf *bf;
int r;
bf = ath_tx_get_buffer(sc);
if (!bf) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n");
+ ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
return -1;
}
@@ -1682,7 +1689,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
if (unlikely(r)) {
struct ath_txq *txq = txctl->txq;
- DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n");
+ ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
/* upon ath_tx_processq() this TX queue will be resumed, we
* guarantee this will happen by knowing beforehand that
@@ -1712,6 +1719,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int hdrlen, padsize;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_tx_control txctl;
@@ -1736,7 +1744,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
if (hdrlen & 3) {
padsize = hdrlen % 4;
if (skb_headroom(skb) < padsize) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n");
+ ath_print(common, ATH_DBG_XMIT,
+ "TX CABQ padding failed\n");
dev_kfree_skb_any(skb);
return;
}
@@ -1746,10 +1755,11 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
txctl.txq = sc->beacon.cabq;
- DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT,
+ "transmitting CABQ packet, skb: %p\n", skb);
if (ath_tx_start(hw, skb, &txctl) != 0) {
- DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n");
+ ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
goto exit;
}
@@ -1768,10 +1778,11 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int hdrlen, padsize;
int frame_type = ATH9K_NOT_INTERNAL;
- DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
if (tx_info_priv) {
hw = tx_info_priv->aphy->hw;
@@ -1805,8 +1816,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
- DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
- "received TX status (0x%x)\n",
+ ath_print(common, ATH_DBG_PS,
+ "Going back to sleep after having "
+ "received TX status (0x%x)\n",
sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
@@ -1936,15 +1948,16 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf, *lastbf, *bf_held = NULL;
struct list_head bf_head;
struct ath_desc *ds;
int txok;
int status;
- DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
- txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
- txq->axq_link);
+ ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
+ txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
+ txq->axq_link);
for (;;) {
spin_lock_bh(&txq->axq_lock);
@@ -2064,8 +2077,11 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
}
if (needreset) {
- DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
+ "tx hung, resetting the chip\n");
+ ath9k_ps_wakeup(sc);
ath_reset(sc, false);
+ ath9k_ps_restore(sc);
}
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
@@ -2093,6 +2109,7 @@ void ath_tx_tasklet(struct ath_softc *sc)
int ath_tx_init(struct ath_softc *sc, int nbufs)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int error = 0;
spin_lock_init(&sc->tx.txbuflock);
@@ -2100,16 +2117,16 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
"tx", nbufs, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate tx descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to allocate tx descriptors: %d\n", error);
goto err;
}
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
"beacon", ATH_BCBUF, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate beacon descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to allocate beacon descriptors: %d\n", error);
goto err;
}
diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c
new file mode 100644
index 00000000000..53e77bd131b
--- /dev/null
+++ b/drivers/net/wireless/ath/debug.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath.h"
+#include "debug.h"
+
+void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
+{
+ va_list args;
+
+ if (likely(!(common->debug_mask & dbg_mask)))
+ return;
+
+ va_start(args, fmt);
+ printk(KERN_DEBUG "ath: ");
+ vprintk(fmt, args);
+ va_end(args);
+}
+EXPORT_SYMBOL(ath_print);
diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h
new file mode 100644
index 00000000000..d6b685a06c5
--- /dev/null
+++ b/drivers/net/wireless/ath/debug.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH_DEBUG_H
+#define ATH_DEBUG_H
+
+#include "ath.h"
+
+/**
+ * enum ath_debug_level - atheros wireless debug level
+ *
+ * @ATH_DBG_RESET: reset processing
+ * @ATH_DBG_QUEUE: hardware queue management
+ * @ATH_DBG_EEPROM: eeprom processing
+ * @ATH_DBG_CALIBRATE: periodic calibration
+ * @ATH_DBG_INTERRUPT: interrupt processing
+ * @ATH_DBG_REGULATORY: regulatory processing
+ * @ATH_DBG_ANI: adaptive noise immunitive processing
+ * @ATH_DBG_XMIT: basic xmit operation
+ * @ATH_DBG_BEACON: beacon handling
+ * @ATH_DBG_CONFIG: configuration of the hardware
+ * @ATH_DBG_FATAL: fatal errors, this is the default, DBG_DEFAULT
+ * @ATH_DBG_PS: power save processing
+ * @ATH_DBG_HWTIMER: hardware timer handling
+ * @ATH_DBG_BTCOEX: bluetooth coexistance
+ * @ATH_DBG_ANY: enable all debugging
+ *
+ * The debug level is used to control the amount and type of debugging output
+ * we want to see. Each driver has its own method for enabling debugging and
+ * modifying debug level states -- but this is typically done through a
+ * module parameter 'debug' along with a respective 'debug' debugfs file
+ * entry.
+ */
+enum ATH_DEBUG {
+ ATH_DBG_RESET = 0x00000001,
+ ATH_DBG_QUEUE = 0x00000002,
+ ATH_DBG_EEPROM = 0x00000004,
+ ATH_DBG_CALIBRATE = 0x00000008,
+ ATH_DBG_INTERRUPT = 0x00000010,
+ ATH_DBG_REGULATORY = 0x00000020,
+ ATH_DBG_ANI = 0x00000040,
+ ATH_DBG_XMIT = 0x00000080,
+ ATH_DBG_BEACON = 0x00000100,
+ ATH_DBG_CONFIG = 0x00000200,
+ ATH_DBG_FATAL = 0x00000400,
+ ATH_DBG_PS = 0x00000800,
+ ATH_DBG_HWTIMER = 0x00001000,
+ ATH_DBG_BTCOEX = 0x00002000,
+ ATH_DBG_ANY = 0xffffffff
+};
+
+#define ATH_DBG_DEFAULT (ATH_DBG_FATAL)
+
+#ifdef CONFIG_ATH_DEBUG
+void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...);
+#else
+static inline void ath_print(struct ath_common *common,
+ int dbg_mask,
+ const char *fmt, ...)
+{
+}
+#endif /* CONFIG_ATH_DEBUG */
+
+#endif /* ATH_DEBUG_H */
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c
new file mode 100644
index 00000000000..ecc9eb01f4f
--- /dev/null
+++ b/drivers/net/wireless/ath/hw.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <asm/unaligned.h>
+
+#include "ath.h"
+#include "reg.h"
+
+#define REG_READ common->ops->read
+#define REG_WRITE common->ops->write
+
+/**
+ * ath_hw_set_bssid_mask - filter out bssids we listen
+ *
+ * @common: the ath_common struct for the device.
+ *
+ * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode and AP mode with a single
+ * BSS every bit matters since we lock to only one BSS. In AP mode with
+ * multiple BSSes (virtual interfaces) not every bit matters because hw must
+ * accept frames for all BSSes and so we tweak some bits of our mac address
+ * in order to have multiple BSSes.
+ *
+ * NOTE: This is a simple filter and does *not* filter out all
+ * relevant frames. Some frames that are not for us might get ACKed from us
+ * by PCU because they just match the mask.
+ *
+ * When handling multiple BSSes you can get the BSSID mask by computing the
+ * set of ~ ( MAC XOR BSSID ) for all bssids we handle.
+ *
+ * When you do this you are essentially computing the common bits of all your
+ * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * the MAC address to obtain the relevant bits and compare the result with
+ * (frame's BSSID & mask) to see if they match.
+ *
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ * \
+ * MAC: 0001 |
+ * BSSID-01: 0100 | --> Belongs to us
+ * BSSID-02: 1001 |
+ * /
+ * -------------------
+ * BSSID-03: 0110 | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ * On loop iteration for BSSID-01:
+ * ~(0001 ^ 0100) -> ~(0101)
+ * -> 1010
+ * bssid_mask = 1010
+ *
+ * On loop iteration for BSSID-02:
+ * bssid_mask &= ~(0001 ^ 1001)
+ * bssid_mask = (1010) & ~(0001 ^ 1001)
+ * bssid_mask = (1010) & ~(1001)
+ * bssid_mask = (1010) & (0110)
+ * bssid_mask = 0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01: 0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is beacuse the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ * --> allow = (0010) == 0000 ? 1 : 0;
+ * --> allow = 0
+ *
+ * Lets now test a frame that should work:
+ *
+ * IFRAME-02: 0001 (we should allow)
+ *
+ * allow = (0001 & 1010) == 1010
+ *
+ * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0;
+ * --> allow = (0010) == (0010)
+ * --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03: 0100 --> allowed
+ * IFRAME-04: 1001 --> allowed
+ * IFRAME-05: 1101 --> allowed but its not for us!!!
+ *
+ */
+void ath_hw_setbssidmask(struct ath_common *common)
+{
+ void *ah = common->ah;
+
+ REG_WRITE(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL);
+ REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU);
+}
+EXPORT_SYMBOL(ath_hw_setbssidmask);
diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h
new file mode 100644
index 00000000000..dfe1fbec24f
--- /dev/null
+++ b/drivers/net/wireless/ath/reg.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH_REGISTERS_H
+#define ATH_REGISTERS_H
+
+/*
+ * BSSID mask registers. See ath_hw_set_bssid_mask()
+ * for detailed documentation about these registers.
+ */
+#define AR_BSSMSKL 0x80e0
+#define AR_BSSMSKU 0x80e4
+
+#endif /* ATH_REGISTERS_H */
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index c1dd857697a..a1c39526161 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -65,10 +65,13 @@ enum CountryCode {
CTRY_ALGERIA = 12,
CTRY_ARGENTINA = 32,
CTRY_ARMENIA = 51,
+ CTRY_ARUBA = 533,
CTRY_AUSTRALIA = 36,
CTRY_AUSTRIA = 40,
CTRY_AZERBAIJAN = 31,
CTRY_BAHRAIN = 48,
+ CTRY_BANGLADESH = 50,
+ CTRY_BARBADOS = 52,
CTRY_BELARUS = 112,
CTRY_BELGIUM = 56,
CTRY_BELIZE = 84,
@@ -77,6 +80,7 @@ enum CountryCode {
CTRY_BRAZIL = 76,
CTRY_BRUNEI_DARUSSALAM = 96,
CTRY_BULGARIA = 100,
+ CTRY_CAMBODIA = 116,
CTRY_CANADA = 124,
CTRY_CHILE = 152,
CTRY_CHINA = 156,
@@ -97,7 +101,11 @@ enum CountryCode {
CTRY_GEORGIA = 268,
CTRY_GERMANY = 276,
CTRY_GREECE = 300,
+ CTRY_GREENLAND = 304,
+ CTRY_GRENEDA = 308,
+ CTRY_GUAM = 316,
CTRY_GUATEMALA = 320,
+ CTRY_HAITI = 332,
CTRY_HONDURAS = 340,
CTRY_HONG_KONG = 344,
CTRY_HUNGARY = 348,
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 9847af72208..248c670fdfb 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -288,13 +288,16 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_DEFAULT, FCC1_FCCA, "CO"},
{CTRY_ALBANIA, NULL1_WORLD, "AL"},
{CTRY_ALGERIA, NULL1_WORLD, "DZ"},
- {CTRY_ARGENTINA, APL3_WORLD, "AR"},
+ {CTRY_ARGENTINA, FCC3_WORLD, "AR"},
{CTRY_ARMENIA, ETSI4_WORLD, "AM"},
+ {CTRY_ARUBA, ETSI1_WORLD, "AW"},
{CTRY_AUSTRALIA, FCC2_WORLD, "AU"},
{CTRY_AUSTRALIA2, FCC6_WORLD, "AU"},
{CTRY_AUSTRIA, ETSI1_WORLD, "AT"},
{CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"},
{CTRY_BAHRAIN, APL6_WORLD, "BH"},
+ {CTRY_BANGLADESH, NULL1_WORLD, "BD"},
+ {CTRY_BARBADOS, FCC2_WORLD, "BB"},
{CTRY_BELARUS, ETSI1_WORLD, "BY"},
{CTRY_BELGIUM, ETSI1_WORLD, "BE"},
{CTRY_BELGIUM2, ETSI4_WORLD, "BL"},
@@ -304,13 +307,14 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_BRAZIL, FCC3_WORLD, "BR"},
{CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"},
{CTRY_BULGARIA, ETSI6_WORLD, "BG"},
- {CTRY_CANADA, FCC2_FCCA, "CA"},
+ {CTRY_CAMBODIA, ETSI1_WORLD, "KH"},
+ {CTRY_CANADA, FCC3_FCCA, "CA"},
{CTRY_CANADA2, FCC6_FCCA, "CA"},
{CTRY_CHILE, APL6_WORLD, "CL"},
{CTRY_CHINA, APL1_WORLD, "CN"},
{CTRY_COLOMBIA, FCC1_FCCA, "CO"},
{CTRY_COSTA_RICA, FCC1_WORLD, "CR"},
- {CTRY_CROATIA, ETSI3_WORLD, "HR"},
+ {CTRY_CROATIA, ETSI1_WORLD, "HR"},
{CTRY_CYPRUS, ETSI1_WORLD, "CY"},
{CTRY_CZECH, ETSI3_WORLD, "CZ"},
{CTRY_DENMARK, ETSI1_WORLD, "DK"},
@@ -324,18 +328,22 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_GEORGIA, ETSI4_WORLD, "GE"},
{CTRY_GERMANY, ETSI1_WORLD, "DE"},
{CTRY_GREECE, ETSI1_WORLD, "GR"},
+ {CTRY_GREENLAND, ETSI1_WORLD, "GL"},
+ {CTRY_GRENEDA, FCC3_FCCA, "GD"},
+ {CTRY_GUAM, FCC1_FCCA, "GU"},
{CTRY_GUATEMALA, FCC1_FCCA, "GT"},
+ {CTRY_HAITI, ETSI1_WORLD, "HT"},
{CTRY_HONDURAS, NULL1_WORLD, "HN"},
- {CTRY_HONG_KONG, FCC2_WORLD, "HK"},
+ {CTRY_HONG_KONG, FCC3_WORLD, "HK"},
{CTRY_HUNGARY, ETSI1_WORLD, "HU"},
{CTRY_ICELAND, ETSI1_WORLD, "IS"},
{CTRY_INDIA, APL6_WORLD, "IN"},
- {CTRY_INDONESIA, APL1_WORLD, "ID"},
+ {CTRY_INDONESIA, NULL1_WORLD, "ID"},
{CTRY_IRAN, APL1_WORLD, "IR"},
{CTRY_IRELAND, ETSI1_WORLD, "IE"},
{CTRY_ISRAEL, NULL1_WORLD, "IL"},
{CTRY_ITALY, ETSI1_WORLD, "IT"},
- {CTRY_JAMAICA, ETSI1_WORLD, "JM"},
+ {CTRY_JAMAICA, FCC3_WORLD, "JM"},
{CTRY_JAPAN, MKK1_MKKA, "JP"},
{CTRY_JAPAN1, MKK1_MKKB, "JP"},
@@ -402,7 +410,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_KOREA_ROC, APL9_WORLD, "KR"},
{CTRY_KOREA_ROC2, APL2_WORLD, "K2"},
{CTRY_KOREA_ROC3, APL9_WORLD, "K3"},
- {CTRY_KUWAIT, NULL1_WORLD, "KW"},
+ {CTRY_KUWAIT, ETSI3_WORLD, "KW"},
{CTRY_LATVIA, ETSI1_WORLD, "LV"},
{CTRY_LEBANON, NULL1_WORLD, "LB"},
{CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"},
@@ -414,13 +422,13 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_MALTA, ETSI1_WORLD, "MT"},
{CTRY_MEXICO, FCC1_FCCA, "MX"},
{CTRY_MONACO, ETSI4_WORLD, "MC"},
- {CTRY_MOROCCO, NULL1_WORLD, "MA"},
+ {CTRY_MOROCCO, APL4_WORLD, "MA"},
{CTRY_NEPAL, APL1_WORLD, "NP"},
{CTRY_NETHERLANDS, ETSI1_WORLD, "NL"},
{CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"},
{CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"},
{CTRY_NORWAY, ETSI1_WORLD, "NO"},
- {CTRY_OMAN, APL6_WORLD, "OM"},
+ {CTRY_OMAN, FCC3_WORLD, "OM"},
{CTRY_PAKISTAN, NULL1_WORLD, "PK"},
{CTRY_PANAMA, FCC1_FCCA, "PA"},
{CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"},
@@ -429,7 +437,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_POLAND, ETSI1_WORLD, "PL"},
{CTRY_PORTUGAL, ETSI1_WORLD, "PT"},
{CTRY_PUERTO_RICO, FCC1_FCCA, "PR"},
- {CTRY_QATAR, NULL1_WORLD, "QA"},
+ {CTRY_QATAR, APL1_WORLD, "QA"},
{CTRY_ROMANIA, NULL1_WORLD, "RO"},
{CTRY_RUSSIA, NULL1_WORLD, "RU"},
{CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"},
@@ -445,7 +453,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_SYRIA, NULL1_WORLD, "SY"},
{CTRY_TAIWAN, APL3_FCCA, "TW"},
{CTRY_THAILAND, FCC3_WORLD, "TH"},
- {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"},
+ {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"},
{CTRY_TUNISIA, ETSI3_WORLD, "TN"},
{CTRY_TURKEY, ETSI3_WORLD, "TR"},
{CTRY_UKRAINE, NULL1_WORLD, "UA"},
@@ -456,7 +464,7 @@ static struct country_code_to_enum_rd allCountries[] = {
* would need to assign new special alpha2 to CRDA db as with the world
* regdomain and use another alpha2 */
{CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"},
- {CTRY_URUGUAY, APL2_WORLD, "UY"},
+ {CTRY_URUGUAY, FCC3_WORLD, "UY"},
{CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"},
{CTRY_VENEZUELA, APL2_ETSIC, "VE"},
{CTRY_VIET_NAM, NULL1_WORLD, "VN"},
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 660716214d4..65b23f725a0 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -749,12 +749,6 @@ struct b43_wldev {
#endif
};
-/*
- * Include goes here to avoid a dependency problem.
- * A better fix would be to integrate xmit.h into b43.h.
- */
-#include "xmit.h"
-
/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
struct b43_wl {
/* Pointer to the active wireless device on this chip */
@@ -830,13 +824,9 @@ struct b43_wl {
struct b43_leds leds;
#ifdef CONFIG_B43_PIO
- /*
- * RX/TX header/tail buffers used by the frame transmit functions.
- */
- struct b43_rxhdr_fw4 rxhdr;
- struct b43_txhdr txhdr;
- u8 rx_tail[4];
- u8 tx_tail[4];
+ /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
+ u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
+ u8 pio_tailspace[4] __attribute__((__aligned__(8)));
#endif /* CONFIG_B43_PIO */
};
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 86f35827f00..ed6e96a3474 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -4670,7 +4670,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
struct ssb_bus *bus = dev->dev->bus;
- struct pci_dev *pdev = bus->host_pci;
+ struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
int err;
bool have_2ghz_phy = 0, have_5ghz_phy = 0;
u32 tmp;
@@ -4803,7 +4803,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
if (!list_empty(&wl->devlist)) {
/* We are not the first core on this chip. */
- pdev = dev->bus->host_pci;
+ pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
/* Only special chips support more than one wireless
* core, although some of the other chips have more than
* one wireless core as well. Check for this and
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 1e318d815a5..c6987b147af 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -379,6 +379,8 @@ static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
}
}
+/* lpphy_restore_dig_flt_state is unused but kept as a reference */
+#if 0
static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
{
static const u16 addr[] = {
@@ -399,6 +401,7 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
for (i = 0; i < ARRAY_SIZE(addr); i++)
b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
}
+#endif
static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
{
@@ -887,6 +890,8 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
}
}
+/* lpphy_disable_rx_gain_override is unused but kept as a reference */
+#if 0
static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
{
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
@@ -902,6 +907,7 @@ static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
}
}
+#endif
static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
{
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index dbbf0d11e18..3105f235303 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -341,12 +341,15 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
q->mmio_base + B43_PIO_TXDATA,
sizeof(u16));
if (data_len & 1) {
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
+
/* Write the last byte. */
ctl &= ~B43_PIO_TXCTL_WRITEHI;
b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
- wl->tx_tail[0] = data[data_len - 1];
- wl->tx_tail[1] = 0;
- ssb_block_write(dev->dev, wl->tx_tail, 2,
+ tail[0] = data[data_len - 1];
+ tail[1] = 0;
+ ssb_block_write(dev->dev, tail, 2,
q->mmio_base + B43_PIO_TXDATA,
sizeof(u16));
}
@@ -392,31 +395,31 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
if (data_len & 3) {
- wl->tx_tail[3] = 0;
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
+
+ memset(tail, 0, 4);
/* Write the last few bytes. */
ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 |
B43_PIO8_TXCTL_24_31);
switch (data_len & 3) {
case 3:
ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15;
- wl->tx_tail[0] = data[data_len - 3];
- wl->tx_tail[1] = data[data_len - 2];
- wl->tx_tail[2] = data[data_len - 1];
+ tail[0] = data[data_len - 3];
+ tail[1] = data[data_len - 2];
+ tail[2] = data[data_len - 1];
break;
case 2:
ctl |= B43_PIO8_TXCTL_8_15;
- wl->tx_tail[0] = data[data_len - 2];
- wl->tx_tail[1] = data[data_len - 1];
- wl->tx_tail[2] = 0;
+ tail[0] = data[data_len - 2];
+ tail[1] = data[data_len - 1];
break;
case 1:
- wl->tx_tail[0] = data[data_len - 1];
- wl->tx_tail[1] = 0;
- wl->tx_tail[2] = 0;
+ tail[0] = data[data_len - 1];
break;
}
b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
- ssb_block_write(dev->dev, wl->tx_tail, 4,
+ ssb_block_write(dev->dev, tail, 4,
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
}
@@ -455,6 +458,7 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
int err;
unsigned int hdrlen;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace;
B43_WARN_ON(list_empty(&q->packets_list));
pack = list_entry(q->packets_list.next,
@@ -462,7 +466,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
cookie = generate_cookie(q, pack);
hdrlen = b43_txhdr_size(dev);
- err = b43_generate_txhdr(dev, (u8 *)&wl->txhdr, skb,
+ BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr));
+ B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen);
+ err = b43_generate_txhdr(dev, (u8 *)txhdr, skb,
info, cookie);
if (err)
return err;
@@ -476,9 +482,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
pack->skb = skb;
if (q->rev >= 8)
- pio_tx_frame_4byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen);
+ pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen);
else
- pio_tx_frame_2byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen);
+ pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen);
/* Remove it from the list of available packet slots.
* It will be put back when we receive the status report. */
@@ -624,8 +630,11 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
unsigned int i, padding;
struct sk_buff *skb;
const char *err_msg = NULL;
+ struct b43_rxhdr_fw4 *rxhdr =
+ (struct b43_rxhdr_fw4 *)wl->pio_scratchspace;
- memset(&wl->rxhdr, 0, sizeof(wl->rxhdr));
+ BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr));
+ memset(rxhdr, 0, sizeof(*rxhdr));
/* Check if we have data and wait for it to get ready. */
if (q->rev >= 8) {
@@ -663,16 +672,16 @@ data_ready:
/* Get the preamble (RX header) */
if (q->rev >= 8) {
- ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr),
+ ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
} else {
- ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr),
+ ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
}
/* Sanity checks. */
- len = le16_to_cpu(wl->rxhdr.frame_len);
+ len = le16_to_cpu(rxhdr->frame_len);
if (unlikely(len > 0x700)) {
err_msg = "len > 0x700";
goto rx_error;
@@ -682,7 +691,7 @@ data_ready:
goto rx_error;
}
- macstat = le32_to_cpu(wl->rxhdr.mac_status);
+ macstat = le32_to_cpu(rxhdr->mac_status);
if (macstat & B43_RX_MAC_FCSERR) {
if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
/* Drop frames with failed FCS. */
@@ -707,22 +716,25 @@ data_ready:
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
if (len & 3) {
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
+
/* Read the last few bytes. */
- ssb_block_read(dev->dev, wl->rx_tail, 4,
+ ssb_block_read(dev->dev, tail, 4,
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
switch (len & 3) {
case 3:
- skb->data[len + padding - 3] = wl->rx_tail[0];
- skb->data[len + padding - 2] = wl->rx_tail[1];
- skb->data[len + padding - 1] = wl->rx_tail[2];
+ skb->data[len + padding - 3] = tail[0];
+ skb->data[len + padding - 2] = tail[1];
+ skb->data[len + padding - 1] = tail[2];
break;
case 2:
- skb->data[len + padding - 2] = wl->rx_tail[0];
- skb->data[len + padding - 1] = wl->rx_tail[1];
+ skb->data[len + padding - 2] = tail[0];
+ skb->data[len + padding - 1] = tail[1];
break;
case 1:
- skb->data[len + padding - 1] = wl->rx_tail[0];
+ skb->data[len + padding - 1] = tail[0];
break;
}
}
@@ -731,15 +743,18 @@ data_ready:
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
if (len & 1) {
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
+
/* Read the last byte. */
- ssb_block_read(dev->dev, wl->rx_tail, 2,
+ ssb_block_read(dev->dev, tail, 2,
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
- skb->data[len + padding - 1] = wl->rx_tail[0];
+ skb->data[len + padding - 1] = tail[0];
}
}
- b43_rx(q->dev, skb, &wl->rxhdr);
+ b43_rx(q->dev, skb, rxhdr);
return 1;
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index f4e9695ec18..7a5e294be2b 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -27,7 +27,7 @@
*/
-#include "b43.h"
+#include "xmit.h"
#include "phy_common.h"
#include "dma.h"
#include "pio.h"
@@ -690,10 +690,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
}
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
-
- local_bh_disable();
- ieee80211_rx(dev->wl->hw, skb);
- local_bh_enable();
+ ieee80211_rx_ni(dev->wl->hw, skb);
#if B43_DEBUG
dev->rx_count++;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 1d9223b3d4c..0983406f463 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3592,7 +3592,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
{
struct b43legacy_wl *wl = dev->wl;
struct ssb_bus *bus = dev->dev->bus;
- struct pci_dev *pdev = bus->host_pci;
+ struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
int err;
int have_bphy = 0;
int have_gphy = 0;
@@ -3706,7 +3706,7 @@ static int b43legacy_one_core_attach(struct ssb_device *dev,
if (!list_empty(&wl->devlist)) {
/* We are not the first core on this chip. */
- pdev = dev->bus->host_pci;
+ pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
/* Only special chips support more than one wireless
* core, although some of the other chips have more than
* one wireless core as well. Check for this and
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig
index c15db229351..08f1e989653 100644
--- a/drivers/net/wireless/hostap/Kconfig
+++ b/drivers/net/wireless/hostap/Kconfig
@@ -2,6 +2,8 @@ config HOSTAP
tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
depends on WLAN_80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_ECB
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig
index a8131384c6b..59ec9eec502 100644
--- a/drivers/net/wireless/ipw2x00/Kconfig
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -6,6 +6,8 @@ config IPW2100
tristate "Intel PRO/Wireless 2100 Network Connection"
depends on PCI && WLAN_80211 && CFG80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
select LIB80211
select LIBIPW
@@ -63,8 +65,10 @@ config IPW2100_DEBUG
config IPW2200
tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
- depends on PCI && WLAN_80211 && CFG80211
+ depends on PCI && WLAN_80211 && CFG80211 && CFG80211_WEXT
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
select LIB80211
select LIBIPW
@@ -152,6 +156,7 @@ config LIBIPW
tristate
depends on PCI && WLAN_80211 && CFG80211
select WIRELESS_EXT
+ select WEXT_SPY
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_ECB
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 8d58e6ed4e7..61ef8904af9 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -11275,6 +11275,7 @@ static int ipw_up(struct ipw_priv *priv)
if (!(priv->config & CFG_CUSTOM_MAC))
eeprom_parse_mac(priv, priv->mac_addr);
memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN);
for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 99310c03325..c82c97be7bf 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,17 +1,7 @@
config IWLWIFI
tristate "Intel Wireless Wifi"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
- select LIB80211
select FW_LOADER
- select MAC80211_LEDS if IWLWIFI_LEDS
- select LEDS_CLASS if IWLWIFI_LEDS
-
-config IWLWIFI_LEDS
- bool "Enable LED support in iwlagn and iwl3945 drivers"
- depends on IWLWIFI
- default y
- ---help---
- Select this if you want LED support.
config IWLWIFI_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwlagn driver"
@@ -50,6 +40,24 @@ config IWLWIFI_DEBUGFS
---help---
Enable creation of debugfs files for the iwlwifi drivers.
+config IWLWIFI_DEVICE_TRACING
+ bool "iwlwifi device access tracing"
+ depends on IWLWIFI
+ depends on EVENT_TRACING
+ help
+ Say Y here to trace all commands, including TX frames and IO
+ accesses, sent to the device. If you say yes, iwlwifi will
+ register with the ftrace framework for event tracing and dump
+ all this information to the ringbuffer, you may need to
+ increase the ringbuffer size. See the ftrace documentation
+ for more information.
+
+ When tracing is not enabled, this option still has some
+ (though rather small) overhead.
+
+ If unsure, say Y so we can help you better when problems
+ occur.
+
config IWLAGN
tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
depends on IWLWIFI
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 1d4e0a226fd..7f82044af24 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,20 +1,22 @@
obj-$(CONFIG_IWLWIFI) += iwlcore.o
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
-iwlcore-objs += iwl-scan.o
+iwlcore-objs += iwl-scan.o iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
-iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
+iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
+CFLAGS_iwl-devtrace.o := -I$(src)
+
+# AGN
obj-$(CONFIG_IWLAGN) += iwlagn.o
-iwlagn-objs := iwl-agn.o iwl-agn-rs.o
+iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
iwlagn-$(CONFIG_IWL5000) += iwl-6000.o
iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
+# 3945
obj-$(CONFIG_IWL3945) += iwl3945.o
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
-
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 2716b91ba9f..3a645e485dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -44,6 +44,7 @@
#include "iwl-sta.h"
#include "iwl-helpers.h"
#include "iwl-5000-hw.h"
+#include "iwl-agn-led.h"
/* Highest firmware API version supported */
#define IWL1000_UCODE_API_MAX 3
@@ -76,7 +77,10 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
/* NIC configuration for 1000 series */
static void iwl1000_nic_config(struct iwl_priv *priv)
{
- iwl5000_nic_config(priv);
+ /* set CSR_HW_CONFIG_REG for uCode use */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
/* Setting digital SVR for 1000 card to 1.32V */
/* locking is acquired in iwl_set_bits_mask_prph() function */
@@ -106,9 +110,8 @@ static struct iwl_lib_ops iwl1000_lib = {
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl1000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -142,6 +145,7 @@ static struct iwl_ops iwl1000_ops = {
.lib = &iwl1000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
struct iwl_cfg iwl1000_bgn_cfg = {
@@ -152,14 +156,48 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.sku = IWL_SKU_G|IWL_SKU_N,
.ops = &iwl1000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = false,
+ .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .support_ct_kill_exit = true,
};
+struct iwl_cfg iwl1000_bg_cfg = {
+ .name = "1000 Series BG",
+ .fw_name_pre = IWL1000_FW_PRE,
+ .ucode_api_max = IWL1000_UCODE_API_MAX,
+ .ucode_api_min = IWL1000_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl1000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = false,
+ .use_bsm = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_1000,
+ .shadow_ram_support = false,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .support_ct_kill_exit = true,
+};
+
+MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 16772780c5b..6fd10d443ba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -71,12 +71,6 @@
#include "iwl-eeprom.h"
-/*
- * uCode queue management definitions ...
- * Queue #4 is the command queue for 3945 and 4965.
- */
-#define IWL_CMD_QUEUE_NUM 4
-
/* Time constants */
#define SHORT_SLOT_TIME 9
#define LONG_SLOT_TIME 20
@@ -254,12 +248,6 @@ struct iwl3945_eeprom {
#define TFD_CTL_PAD_SET(n) (n << 28)
#define TFD_CTL_PAD_GET(ctl) (ctl >> 28)
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
/* Sizes and addresses for instruction and data memory (SRAM) in
* 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */
#define IWL39_RTC_INST_LOWER_BOUND (0x000000)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 8c29ded7d02..a871d09d598 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -24,8 +24,6 @@
*
*****************************************************************************/
-#ifdef CONFIG_IWLWIFI_LEDS
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -43,388 +41,51 @@
#include "iwl-3945.h"
#include "iwl-core.h"
#include "iwl-dev.h"
+#include "iwl-3945-led.h"
-#ifdef CONFIG_IWLWIFI_DEBUG
-static const char *led_type_str[] = {
- __stringify(IWL_LED_TRG_TX),
- __stringify(IWL_LED_TRG_RX),
- __stringify(IWL_LED_TRG_ASSOC),
- __stringify(IWL_LED_TRG_RADIO),
- NULL
-};
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-static const struct {
- u16 brightness;
- u8 on_time;
- u8 off_time;
-} blink_tbl[] =
-{
- {300, 25, 25},
- {200, 40, 40},
- {100, 55, 55},
- {70, 65, 65},
- {50, 75, 75},
- {20, 85, 85},
- {15, 95, 95 },
- {10, 110, 110},
- {5, 130, 130},
- {0, 167, 167},
- /* SOLID_ON */
- {-1, IWL_LED_SOLID, 0}
-};
-
-#define IWL_1MB_RATE (128 * 1024)
-#define IWL_LED_THRESHOLD (16)
-#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
-#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
-
-static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
- struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
-{
-}
-
-static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
-{
- return fls(0x000000FF & (u32)brightness);
-}
/* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv,
- struct iwl_led_cmd *led_cmd)
+static int iwl3945_send_led_cmd(struct iwl_priv *priv,
+ struct iwl_led_cmd *led_cmd)
{
struct iwl_host_cmd cmd = {
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
.flags = CMD_ASYNC,
- .callback = iwl3945_led_cmd_callback,
+ .callback = NULL,
};
return iwl_send_cmd(priv, &cmd);
}
-
-
-/* Set led on command */
-static int iwl3945_led_pattern(struct iwl_priv *priv, int led_id,
- unsigned int idx)
-{
- struct iwl_led_cmd led_cmd = {
- .id = led_id,
- .interval = IWL_DEF_LED_INTRVL
- };
-
- BUG_ON(idx > IWL_MAX_BLINK_TBL);
-
- led_cmd.on = blink_tbl[idx].on_time;
- led_cmd.off = blink_tbl[idx].off_time;
-
- return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-
/* Set led on command */
-static int iwl3945_led_on(struct iwl_priv *priv, int led_id)
+static int iwl3945_led_on(struct iwl_priv *priv)
{
struct iwl_led_cmd led_cmd = {
- .id = led_id,
+ .id = IWL_LED_LINK,
.on = IWL_LED_SOLID,
.off = 0,
.interval = IWL_DEF_LED_INTRVL
};
- return iwl_send_led_cmd(priv, &led_cmd);
+ return iwl3945_send_led_cmd(priv, &led_cmd);
}
/* Set led off command */
-static int iwl3945_led_off(struct iwl_priv *priv, int led_id)
+static int iwl3945_led_off(struct iwl_priv *priv)
{
struct iwl_led_cmd led_cmd = {
- .id = led_id,
+ .id = IWL_LED_LINK,
.on = 0,
.off = 0,
.interval = IWL_DEF_LED_INTRVL
};
- IWL_DEBUG_LED(priv, "led off %d\n", led_id);
- return iwl_send_led_cmd(priv, &led_cmd);
+ IWL_DEBUG_LED(priv, "led off\n");
+ return iwl3945_send_led_cmd(priv, &led_cmd);
}
-/*
- * Set led on in case of association
- * */
-static int iwl3945_led_associate(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "Associated\n");
-
- priv->allow_blinking = 1;
- return iwl3945_led_on(priv, led_id);
-}
-/* Set Led off in case of disassociation */
-static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "Disassociated\n");
-
- priv->allow_blinking = 0;
-
- return 0;
-}
-
-/*
- * brightness call back function for Tx/Rx LED
- */
-static int iwl3945_led_associated(struct iwl_priv *priv, int led_id)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
- !test_bit(STATUS_READY, &priv->status))
- return 0;
-
-
- /* start counting Tx/Rx bytes */
- if (!priv->last_blink_time && priv->allow_blinking)
- priv->last_blink_time = jiffies;
- return 0;
-}
-
-/*
- * brightness call back for association and radio
- */
-static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct iwl_led *led = container_of(led_cdev,
- struct iwl_led, led_dev);
- struct iwl_priv *priv = led->priv;
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n",
- led_type_str[led->type], brightness);
-
- switch (brightness) {
- case LED_FULL:
- if (led->led_on)
- led->led_on(priv, IWL_LED_LINK);
- break;
- case LED_OFF:
- if (led->led_off)
- led->led_off(priv, IWL_LED_LINK);
- break;
- default:
- if (led->led_pattern) {
- int idx = iwl3945_brightness_to_idx(brightness);
- led->led_pattern(priv, IWL_LED_LINK, idx);
- }
- break;
- }
-}
-
-/*
- * Register led class with the system
- */
-static int iwl3945_led_register_led(struct iwl_priv *priv,
- struct iwl_led *led,
- enum led_type type, u8 set_led,
- char *trigger)
-{
- struct device *device = wiphy_dev(priv->hw->wiphy);
- int ret;
-
- led->led_dev.name = led->name;
- led->led_dev.brightness_set = iwl3945_led_brightness_set;
- led->led_dev.default_trigger = trigger;
-
- led->priv = priv;
- led->type = type;
-
- ret = led_classdev_register(device, &led->led_dev);
- if (ret) {
- IWL_ERR(priv, "Error: failed to register led handler.\n");
- return ret;
- }
-
- led->registered = 1;
-
- if (set_led && led->led_on)
- led->led_on(priv, IWL_LED_LINK);
- return 0;
-}
-
-
-/*
- * calculate blink rate according to last 2 sec Tx/Rx activities
- */
-static inline u8 get_blink_rate(struct iwl_priv *priv)
-{
- int index;
- s64 tpt = priv->rxtxpackets;
-
- if (tpt < 0)
- tpt = -tpt;
-
- IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt);
-
- if (!priv->allow_blinking)
- index = IWL_MAX_BLINK_TBL;
- else
- for (index = 0; index < IWL_MAX_BLINK_TBL; index++)
- if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE))
- break;
-
- IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index);
- return index;
-}
-
-/*
- * this function called from handler. Since setting Led command can
- * happen very frequent we postpone led command to be called from
- * REPLY handler so we know ucode is up
- */
-void iwl3945_led_background(struct iwl_priv *priv)
-{
- u8 blink_idx;
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
- priv->last_blink_time = 0;
- return;
- }
- if (iwl_is_rfkill(priv)) {
- priv->last_blink_time = 0;
- return;
- }
-
- if (!priv->allow_blinking) {
- priv->last_blink_time = 0;
- if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
- priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
- iwl3945_led_pattern(priv, IWL_LED_LINK,
- IWL_SOLID_BLINK_IDX);
- }
- return;
- }
- if (!priv->last_blink_time ||
- !time_after(jiffies, priv->last_blink_time +
- msecs_to_jiffies(1000)))
- return;
-
- blink_idx = get_blink_rate(priv);
-
- /* call only if blink rate change */
- if (blink_idx != priv->last_blink_rate)
- iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx);
-
- priv->last_blink_time = jiffies;
- priv->last_blink_rate = blink_idx;
- priv->rxtxpackets = 0;
-}
-
-
-/* Register all led handler */
-int iwl3945_led_register(struct iwl_priv *priv)
-{
- char *trigger;
- int ret;
-
- priv->last_blink_rate = 0;
- priv->rxtxpackets = 0;
- priv->led_tpt = 0;
- priv->last_blink_time = 0;
- priv->allow_blinking = 0;
-
- trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RADIO].name,
- sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
- wiphy_name(priv->hw->wiphy));
-
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off;
- priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_RADIO],
- IWL_LED_TRG_RADIO, 1, trigger);
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
- sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_ASSOC],
- IWL_LED_TRG_ASSOC, 0, trigger);
-
- /* for assoc always turn led on */
- priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate;
- priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate;
- priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RX].name,
- sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_RX],
- IWL_LED_TRG_RX, 0, trigger);
-
- priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_TX].name,
- sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_TX],
- IWL_LED_TRG_TX, 0, trigger);
-
- priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- return 0;
-
-exit_fail:
- iwl3945_led_unregister(priv);
- return ret;
-}
-
-
-/* unregister led class */
-static void iwl3945_led_unregister_led(struct iwl_led *led, u8 set_led)
-{
- if (!led->registered)
- return;
-
- led_classdev_unregister(&led->led_dev);
-
- if (set_led)
- led->led_dev.brightness_set(&led->led_dev, LED_OFF);
- led->registered = 0;
-}
-
-/* Unregister all led handlers */
-void iwl3945_led_unregister(struct iwl_priv *priv)
-{
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
-}
-
-#endif
+const struct iwl_led_ops iwl3945_led_ops = {
+ .cmd = iwl3945_send_led_cmd,
+ .on = iwl3945_led_on,
+ .off = iwl3945_led_off,
+};
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index 3b65642258c..5a1033ca7aa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -24,23 +24,9 @@
*
*****************************************************************************/
-#ifndef IWL3945_LEDS_H
-#define IWL3945_LEDS_H
+#ifndef __iwl_3945_led_h__
+#define __iwl_3945_led_h__
-struct iwl_priv;
+extern const struct iwl_led_ops iwl3945_led_ops;
-#ifdef CONFIG_IWLWIFI_LEDS
-
-#include "iwl-led.h"
-
-extern int iwl3945_led_register(struct iwl_priv *priv);
-extern void iwl3945_led_unregister(struct iwl_priv *priv);
-extern void iwl3945_led_background(struct iwl_priv *priv);
-
-#else
-static inline int iwl3945_led_register(struct iwl_priv *priv) { return 0; }
-static inline void iwl3945_led_unregister(struct iwl_priv *priv) {}
-static inline void iwl3945_led_background(struct iwl_priv *priv) {}
-
-#endif /* IWLWIFI_LEDS*/
-#endif /* IWL3945_LEDS_H */
+#endif /* __iwl_3945_led_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 231c833f646..09a7bd2c0be 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -46,7 +46,8 @@
#include "iwl-eeprom.h"
#include "iwl-helpers.h"
#include "iwl-core.h"
-#include "iwl-agn-rs.h"
+#include "iwl-led.h"
+#include "iwl-3945-led.h"
#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
@@ -292,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -352,16 +353,12 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl3945_notif_statistics),
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
-
- iwl3945_led_background(priv);
-
- priv->last_statistics_time = jiffies;
}
/******************************************************************************
@@ -544,14 +541,18 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
- short len = le16_to_cpu(rx_hdr->len);
+ u16 len = le16_to_cpu(rx_hdr->len);
+ struct sk_buff *skb;
+ int ret;
+ __le16 fc = hdr->frame_control;
/* We received data from the HW, so stop the watchdog */
- if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
+ if (unlikely(len + IWL39_RX_FRAME_SIZE >
+ PAGE_SIZE << priv->hw_params.rx_page_order)) {
IWL_DEBUG_DROP(priv, "Corruption detected!\n");
return;
}
@@ -563,24 +564,49 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
return;
}
- skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
+ skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
+ if (!skb) {
+ IWL_ERR(priv, "alloc_skb failed\n");
+ return;
+ }
if (!iwl3945_mod_params.sw_crypto)
iwl_set_decrypted_flag(priv,
- (struct ieee80211_hdr *)rxb->skb->data,
+ (struct ieee80211_hdr *)rxb_addr(rxb),
le32_to_cpu(rx_end->status), stats);
-#ifdef CONFIG_IWLWIFI_LEDS
- if (ieee80211_is_data(hdr->frame_control))
- priv->rxtxpackets += len;
-#endif
- iwl_update_stats(priv, false, hdr->frame_control, len);
+ skb_add_rx_frag(skb, 0, rxb->page,
+ (void *)rx_hdr->payload - (void *)pkt, len);
+
+ /* mac80211 currently doesn't support paged SKB. Convert it to
+ * linear SKB for management frame and data frame requires
+ * software decryption or software defragementation. */
+ if (ieee80211_is_mgmt(fc) ||
+ ieee80211_has_protected(fc) ||
+ ieee80211_has_morefrags(fc) ||
+ le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
+ ret = skb_linearize(skb);
+ else
+ ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
+ 0 : -ENOMEM;
+
+ if (ret) {
+ kfree_skb(skb);
+ goto out;
+ }
- memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
- ieee80211_rx_irqsafe(priv->hw, rxb->skb);
- rxb->skb = NULL;
+ /*
+ * XXX: We cannot touch the page and its virtual memory (pkt) after
+ * here. It might have already been freed by the above skb change.
+ */
+
+ iwl_update_stats(priv, false, fc, len);
+ memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+ ieee80211_rx(priv->hw, skb);
+ out:
+ priv->alloc_rxb_page--;
+ rxb->page = NULL;
}
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
@@ -590,7 +616,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
{
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
@@ -790,29 +816,31 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
u8 data_retry_limit;
__le32 tx_flags;
__le16 fc = hdr->frame_control;
- struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
+ struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
rate = iwl3945_rates[rate_index].plcp;
- tx_flags = tx->tx_flags;
+ tx_flags = tx_cmd->tx_flags;
/* We need to figure out how to get the sta->supp_rates while
* in this running context */
rate_mask = IWL_RATES_MASK;
+
+ /* Set retry limit on DATA packets and Probe Responses*/
+ if (ieee80211_is_probe_resp(fc))
+ data_retry_limit = 3;
+ else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+ tx_cmd->data_retry_limit = data_retry_limit;
+
if (tx_id >= IWL_CMD_QUEUE_NUM)
rts_retry_limit = 3;
else
rts_retry_limit = 7;
- if (ieee80211_is_probe_resp(fc)) {
- data_retry_limit = 3;
- if (data_retry_limit < rts_retry_limit)
- rts_retry_limit = data_retry_limit;
- } else
- data_retry_limit = IWL_DEFAULT_TX_RETRY;
-
- if (priv->data_retry_limit != -1)
- data_retry_limit = priv->data_retry_limit;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ tx_cmd->rts_retry_limit = rts_retry_limit;
if (ieee80211_is_mgmt(fc)) {
switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
@@ -830,22 +858,20 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
}
}
- tx->rts_retry_limit = rts_retry_limit;
- tx->data_retry_limit = data_retry_limit;
- tx->rate = rate;
- tx->tx_flags = tx_flags;
+ tx_cmd->rate = rate;
+ tx_cmd->tx_flags = tx_flags;
/* OFDM */
- tx->supp_rates[0] =
+ tx_cmd->supp_rates[0] =
((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF;
/* CCK */
- tx->supp_rates[1] = (rate_mask & 0xF);
+ tx_cmd->supp_rates[1] = (rate_mask & 0xF);
IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
"cck/ofdm mask: 0x%x/0x%x\n", sta_id,
- tx->rate, le32_to_cpu(tx->tx_flags),
- tx->supp_rates[1], tx->supp_rates[0]);
+ tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags),
+ tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
}
u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
@@ -961,6 +987,11 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_free(priv);
+ /* allocate tx queue structure */
+ rc = iwl_alloc_txq_mem(priv);
+ if (rc)
+ return rc;
+
/* Tx CMD queue */
rc = iwl3945_tx_reset(priv);
if (rc)
@@ -985,41 +1016,25 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
return rc;
}
+
+/*
+ * Start up 3945's basic functionality after it has been reset
+ * (e.g. after platform boot, or shutdown via iwl_apm_stop())
+ * NOTE: This does not load uCode nor start the embedded processor
+ */
static int iwl3945_apm_init(struct iwl_priv *priv)
{
- int ret;
-
- iwl_power_initialize(priv);
-
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ int ret = iwl_apm_init(priv);
- /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- goto out;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- udelay(20);
+ /* Clear APMG (NIC's internal power management) interrupts */
+ iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
+ iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF);
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ /* Reset radio chip */
+ iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
+ udelay(5);
+ iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
-out:
return ret;
}
@@ -1144,12 +1159,16 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- if (txq_id == IWL_CMD_QUEUE_NUM)
- iwl_cmd_queue_free(priv);
- else
- iwl_tx_queue_free(priv, txq_id);
+ if (priv->txq)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
+ txq_id++)
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ iwl_cmd_queue_free(priv);
+ else
+ iwl_tx_queue_free(priv, txq_id);
+ /* free tx queue structure */
+ iwl_free_txq_mem(priv);
}
void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
@@ -1158,6 +1177,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
/* stop SCD */
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
+ iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0);
/* reset TFD queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
@@ -1170,85 +1190,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_free(priv);
}
-static int iwl3945_apm_stop_master(struct iwl_priv *priv)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* set stop master bit */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
- iwl_poll_direct_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-
- if (ret < 0)
- goto out;
-
-out:
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_INFO(priv, "stop master\n");
-
- return ret;
-}
-
-static void iwl3945_apm_stop(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- iwl3945_apm_stop_master(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
- /* clear "init complete" move adapter D0A* --> D0U state */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int iwl3945_apm_reset(struct iwl_priv *priv)
-{
- iwl3945_apm_stop_master(priv);
-
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
- udelay(10);
-
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-
- iwl_write_prph(priv, APMG_CLK_CTRL_REG,
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
- iwl_write_prph(priv, APMG_RTC_INT_STT_REG,
- 0xFFFFFFFF);
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_EN_REG,
- APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
- udelay(10);
-
- iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_RESET_REQ);
- udelay(5);
- iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_RESET_REQ);
-
- /* Clear the 'host command active' bit... */
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-
- wake_up_interruptible(&priv->wait_command_queue);
-
- return 0;
-}
-
/**
* iwl3945_hw_reg_adjust_power_by_temp
* return index delta into power gain settings table
@@ -1857,7 +1798,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
{
int rc = 0;
- struct iwl_rx_packet *res = NULL;
+ struct iwl_rx_packet *pkt;
struct iwl3945_rxon_assoc_cmd rxon_assoc;
struct iwl_host_cmd cmd = {
.id = REPLY_RXON_ASSOC,
@@ -1886,14 +1827,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
rc = -EIO;
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return rc;
}
@@ -2041,12 +1982,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
return 0;
}
-/* will add 3945 channel switch cmd handling later */
-int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel)
-{
- return 0;
-}
-
/**
* iwl3945_reg_txpower_periodic - called when time to check our temperature.
*
@@ -2556,11 +2491,10 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
}
/* Assign number of Usable TX queues */
- priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
- priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
- priv->hw_params.max_pkt_size = 2342;
+ priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K);
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
priv->hw_params.max_stations = IWL3945_STATION_COUNT;
@@ -2843,8 +2777,7 @@ static struct iwl_lib_ops iwl3945_lib = {
.dump_nic_error_log = iwl3945_dump_nic_error_log,
.apm_ops = {
.init = iwl3945_apm_init,
- .reset = iwl3945_apm_reset,
- .stop = iwl3945_apm_stop,
+ .stop = iwl_apm_stop,
.config = iwl3945_nic_config,
.set_pwr_src = iwl3945_set_pwr_src,
},
@@ -2873,6 +2806,7 @@ static struct iwl_lib_ops iwl3945_lib = {
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
.get_hcmd_size = iwl3945_get_hcmd_size,
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
+ .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
};
static struct iwl_ops iwl3945_ops = {
@@ -2880,6 +2814,7 @@ static struct iwl_ops iwl3945_ops = {
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
+ .led = &iwl3945_led_ops,
};
static struct iwl_cfg iwl3945_bg_cfg = {
@@ -2891,9 +2826,14 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.eeprom_size = IWL3945_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops,
+ .num_of_queues = IWL39_NUM_QUEUES,
.mod_params = &iwl3945_mod_params,
+ .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
+ .set_l0s = false,
+ .use_bsm = true,
.use_isr_legacy = true,
.ht_greenfield_support = false,
+ .led_compensation = 64,
};
static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2905,9 +2845,11 @@ static struct iwl_cfg iwl3945_abg_cfg = {
.eeprom_size = IWL3945_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops,
+ .num_of_queues = IWL39_NUM_QUEUES,
.mod_params = &iwl3945_mod_params,
.use_isr_legacy = true,
.ht_greenfield_support = false,
+ .led_compensation = 64,
};
struct pci_device_id iwl3945_hw_card_ids[] = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 21679bf3a1a..ebb999a51b5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -46,7 +46,7 @@ extern struct pci_device_id iwl3945_hw_card_ids[];
#include "iwl-debug.h"
#include "iwl-power.h"
#include "iwl-dev.h"
-#include "iwl-3945-led.h"
+#include "iwl-led.h"
/* Highest firmware API version supported */
#define IWL3945_UCODE_API_MAX 2
@@ -130,12 +130,6 @@ struct iwl3945_frame {
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
@@ -280,8 +274,6 @@ extern void iwl3945_config_ap(struct iwl_priv *priv);
*/
extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
-extern int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel);
-
/*
* Forward declare iwl-3945.c functions for iwl-base.c
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index b34322a3245..c606366b582 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -76,12 +76,9 @@
/*
* uCode queue management definitions ...
- * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4.
* The first queue used for block-ack aggregation is #7 (4965 only).
* All block-ack aggregation queues should map to Tx DMA/FIFO channel 7.
*/
-#define IWL_CMD_QUEUE_NUM 4
-#define IWL_CMD_FIFO_NUM 4
#define IWL49_FIRST_AMPDU_QUEUE 7
/* Time constants */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index a22a0501c19..1ff465ad40d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -44,6 +44,7 @@
#include "iwl-helpers.h"
#include "iwl-calib.h"
#include "iwl-sta.h"
+#include "iwl-agn-led.h"
static int iwl4965_send_tx_power(struct iwl_priv *priv);
static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
@@ -61,8 +62,6 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
/* module parameters */
static struct iwl_mod_params iwl4965_mod_params = {
- .num_of_queues = IWL49_NUM_QUEUES,
- .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
.amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -318,63 +317,13 @@ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask)
iwl_write_prph(priv, IWL49_SCD_TXFACT, mask);
}
-static int iwl4965_apm_init(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
- /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- /* wait for clock stabilization */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- goto out;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- udelay(20);
-
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-out:
- return ret;
-}
-
-
static void iwl4965_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
u16 radio_cfg;
- u16 lctl;
spin_lock_irqsave(&priv->lock, flags);
- lctl = iwl_pcie_link_ctl(priv);
-
- /* HW bug W/A - negligible power consumption */
- /* L1-ASPM is enabled by BIOS */
- if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
- /* L1-ASPM enabled: disable L0S */
- iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
- else
- /* L1-ASPM disabled: enable L0S */
- iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
/* write radio config values to register */
@@ -395,79 +344,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
-static int iwl4965_apm_stop_master(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* set stop master bit */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
- iwl_poll_direct_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_INFO(priv, "stop master\n");
-
- return 0;
-}
-
-static void iwl4965_apm_stop(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- iwl4965_apm_stop_master(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
- /* clear "init complete" move adapter D0A* --> D0U state */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int iwl4965_apm_reset(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl4965_apm_stop_master(priv);
-
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
-
- /* FIXME: put here L1A -L0S w/a */
-
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0)
- goto out;
-
- udelay(10);
-
- /* Enable DMA and BSM Clock */
- iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- udelay(10);
-
- /* disable L1A */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
- wake_up_interruptible(&priv->wait_command_queue);
-
-out:
- return ret;
-}
-
/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
* Called after every association, but this runs only once!
* ... once chain noise is calibrated the first time, it's good forever. */
@@ -495,14 +371,15 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
static void iwl4965_gain_computation(struct iwl_priv *priv,
u32 *average_noise,
u16 min_average_noise_antenna_i,
- u32 min_average_noise)
+ u32 min_average_noise,
+ u8 default_chain)
{
int i, ret;
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
data->delta_gain_code[min_average_noise_antenna_i] = 0;
- for (i = 0; i < NUM_RX_CHAINS; i++) {
+ for (i = default_chain; i < NUM_RX_CHAINS; i++) {
s32 delta_g = 0;
if (!(data->disconn_array[i]) &&
@@ -556,18 +433,6 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
data->beacon_count = 0;
}
-static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
- __le32 *tx_flags)
-{
- if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- *tx_flags |= TX_CMD_FLG_RTS_MSK;
- *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- *tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
-}
-
static void iwl4965_bg_txpower_work(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -662,7 +527,8 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
iwl_write_targ_mem(priv, a, 0);
for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4)
iwl_write_targ_mem(priv, a, 0);
- for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
+ for (; a < priv->scd_base_addr +
+ IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
iwl_write_targ_mem(priv, a, 0);
/* Tel 4965 where to find Tx byte count tables */
@@ -747,6 +613,10 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.nrg_th_cck = 100,
.nrg_th_ofdm = 100,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
};
static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
@@ -763,19 +633,16 @@ static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
*/
static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
{
+ if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ priv->cfg->mod_params->num_of_queues <= IWL49_NUM_QUEUES)
+ priv->cfg->num_of_queues =
+ priv->cfg->mod_params->num_of_queues;
- if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) ||
- (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
- IWL_ERR(priv,
- "invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES);
- return -EINVAL;
- }
-
- priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl);
+ priv->cfg->num_of_queues *
+ sizeof(struct iwl4965_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL4965_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
@@ -786,10 +653,10 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
- priv->hw_params.tx_chains_num = 2;
- priv->hw_params.rx_chains_num = 2;
- priv->hw_params.valid_tx_ant = ANT_A | ANT_B;
- priv->hw_params.valid_rx_ant = ANT_A | ANT_B;
+ priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+ priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
@@ -1566,14 +1433,13 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-#ifdef IEEE80211_CONF_CHANNEL_SWITCH
static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
int rc;
u8 band = 0;
bool is_ht40 = false;
u8 ctrl_chan_high = 0;
- struct iwl4965_channel_switch_cmd cmd = { 0 };
+ struct iwl4965_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
band = priv->band == IEEE80211_BAND_2GHZ;
@@ -1594,8 +1460,11 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
- else
- cmd.expect_beacon = 1;
+ else {
+ IWL_ERR(priv, "invalid channel switch from %u to %u\n",
+ priv->active_rxon.channel, channel);
+ return -EFAULT;
+ }
rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
ctrl_chan_high, &cmd.tx_power);
@@ -1607,7 +1476,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
return rc;
}
-#endif
/**
* iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
@@ -1804,11 +1672,13 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+ <= txq_id)) {
IWL_WARN(priv,
"queue number out of range: %d, must be %d to %d\n",
txq_id, IWL49_FIRST_AMPDU_QUEUE,
- IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
+ IWL49_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -1869,11 +1739,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
u16 ra_tid;
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+ <= txq_id)) {
IWL_WARN(priv,
"queue number out of range: %d, must be %d to %d\n",
txq_id, IWL49_FIRST_AMPDU_QUEUE,
- IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
+ IWL49_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -2077,7 +1949,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -2278,7 +2150,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
.chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation,
- .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
+ .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
.calc_rssi = iwl4965_calc_rssi,
};
@@ -2300,10 +2172,10 @@ static struct iwl_lib_ops iwl4965_lib = {
.load_ucode = iwl4965_load_bsm,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
+ .set_channel_switch = iwl4965_hw_channel_switch,
.apm_ops = {
- .init = iwl4965_apm_init,
- .reset = iwl4965_apm_reset,
- .stop = iwl4965_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl4965_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -2339,6 +2211,7 @@ static struct iwl_ops iwl4965_ops = {
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
struct iwl_cfg iwl4965_agn_cfg = {
@@ -2351,30 +2224,40 @@ struct iwl_cfg iwl4965_agn_cfg = {
.eeprom_ver = EEPROM_4965_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
.ops = &iwl4965_ops,
+ .num_of_queues = IWL49_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
.mod_params = &iwl4965_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = true,
.use_isr_legacy = true,
.ht_greenfield_support = false,
.broken_powersave = true,
+ .led_compensation = 61,
+ .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
};
/* Module firmware */
MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
-module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
+module_param_named(antenna, iwl4965_mod_params.antenna, int, S_IRUGO);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
+module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(
- disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
+ disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, S_IRUGO);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444);
+module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, S_IRUGO);
MODULE_PARM_DESC(queues_num, "number of hw queues.");
/* 11n */
-module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444);
+module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, S_IRUGO);
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
-module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444);
+module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K,
+ int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 524e7e4c51d..d256fecc6cd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -42,6 +42,7 @@
#include "iwl-io.h"
#include "iwl-sta.h"
#include "iwl-helpers.h"
+#include "iwl-agn-led.h"
#include "iwl-5000-hw.h"
#include "iwl-6000-hw.h"
@@ -71,157 +72,18 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_HCCA_2
};
-/* FIXME: same implementation as 4965 */
-static int iwl5000_apm_stop_master(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* set stop master bit */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
- iwl_poll_direct_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_INFO(priv, "stop master\n");
-
- return 0;
-}
-
-
-int iwl5000_apm_init(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
- /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
- /* Set FH wait threshold to maximum (HW error during stress W/A) */
- iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
-
- /* enable HAP INTA to move device L1a -> L0s */
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
-
- if (priv->cfg->need_pll_cfg)
- iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- /* wait for clock stabilization */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- return ret;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-
- udelay(20);
-
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
- return ret;
-}
-
-/* FIXME: this is identical to 4965 */
-void iwl5000_apm_stop(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- iwl5000_apm_stop_master(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
-
- /* clear "init complete" move adapter D0A* --> D0U state */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-
-int iwl5000_apm_reset(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl5000_apm_stop_master(priv);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
-
-
- /* FIXME: put here L1A -L0S w/a */
-
- if (priv->cfg->need_pll_cfg)
- iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- /* wait for clock stabilization */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- goto out;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-
- udelay(20);
-
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-out:
-
- return ret;
-}
-
-
-/* NIC configuration for 5000 series and up */
+/* NIC configuration for 5000 series */
void iwl5000_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
u16 radio_cfg;
- u16 lctl;
spin_lock_irqsave(&priv->lock, flags);
- lctl = iwl_pcie_link_ctl(priv);
-
- /* HW bug W/A */
- /* L1-ASPM is enabled by BIOS */
- if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
- /* L1-APSM enabled: disable L0S */
- iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
- else
- /* L1-ASPM disabled: enable L0S */
- iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
/* write radio config values to register */
- if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX)
+ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_RF_CONFIG_TYPE_MAX)
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
@@ -301,19 +163,22 @@ u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
static void iwl5000_gain_computation(struct iwl_priv *priv,
u32 average_noise[NUM_RX_CHAINS],
u16 min_average_noise_antenna_i,
- u32 min_average_noise)
+ u32 min_average_noise,
+ u8 default_chain)
{
int i;
s32 delta_g;
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
- /* Find Gain Code for the antennas B and C */
- for (i = 1; i < NUM_RX_CHAINS; i++) {
+ /*
+ * Find Gain Code for the chains based on "default chain"
+ */
+ for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
if ((data->disconn_array[i])) {
data->delta_gain_code[i] = 0;
continue;
}
- delta_g = (1000 * ((s32)average_noise[0] -
+ delta_g = (1000 * ((s32)average_noise[default_chain] -
(s32)average_noise[i])) / 1500;
/* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] =
@@ -406,6 +271,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.auto_corr_max_cck_mrc = 400,
.nrg_th_cck = 95,
.nrg_th_ofdm = 95,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
};
static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
@@ -428,6 +297,10 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
.auto_corr_max_cck_mrc = 400,
.nrg_th_cck = 95,
.nrg_th_ofdm = 95,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
};
const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
@@ -492,7 +365,7 @@ static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
static void iwl5000_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
int index;
@@ -745,7 +618,8 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
a += 4)
iwl_write_targ_mem(priv, a, 0);
- for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
+ for (; a < priv->scd_base_addr +
+ IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
iwl_write_targ_mem(priv, a, 0);
iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
@@ -817,32 +691,22 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
{
- if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
- (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
- IWL_ERR(priv,
- "invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES);
- return -EINVAL;
- }
+ if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+ priv->cfg->num_of_queues =
+ priv->cfg->mod_params->num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl);
+ priv->cfg->num_of_queues *
+ sizeof(struct iwl5000_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
- case CSR_HW_REV_TYPE_6x00:
- case CSR_HW_REV_TYPE_6x50:
- priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
- break;
- default:
- priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
- }
+ priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
+ priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
priv->hw_params.max_bsm_size = 0;
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
@@ -988,11 +852,13 @@ int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
u16 ra_tid;
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+ <= txq_id)) {
IWL_WARN(priv,
"queue number out of range: %d, must be %d to %d\n",
txq_id, IWL50_FIRST_AMPDU_QUEUE,
- IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+ IWL50_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -1046,11 +912,13 @@ int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+ <= txq_id)) {
IWL_ERR(priv,
"queue number out of range: %d, must be %d to %d\n",
txq_id, IWL50_FIRST_AMPDU_QUEUE,
- IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+ IWL50_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -1217,7 +1085,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -1458,6 +1326,24 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+static int iwl5000_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+{
+ struct iwl_tx_ant_config_cmd tx_ant_cmd = {
+ .valid = cpu_to_le32(valid_tx_ant),
+ };
+
+ if (IWL_UCODE_API(priv->ucode_ver) > 1) {
+ IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
+ return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
+ sizeof(struct iwl_tx_ant_config_cmd),
+ &tx_ant_cmd);
+ } else {
+ IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
+ return -EOPNOTSUPP;
+ }
+}
+
+
#define IWL5000_UCODE_GET(item) \
static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
@@ -1496,10 +1382,41 @@ IWL5000_UCODE_GET(init_size);
IWL5000_UCODE_GET(init_data_size);
IWL5000_UCODE_GET(boot_size);
+static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ struct iwl5000_channel_switch_cmd cmd;
+ const struct iwl_channel_info *ch_info;
+ struct iwl_host_cmd hcmd = {
+ .id = REPLY_CHANNEL_SWITCH,
+ .len = sizeof(cmd),
+ .flags = CMD_SIZE_HUGE,
+ .data = &cmd,
+ };
+
+ IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+ priv->active_rxon.channel, channel);
+ cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+ cmd.channel = cpu_to_le16(channel);
+ cmd.rxon_flags = priv->active_rxon.flags;
+ cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ if (ch_info)
+ cmd.expect_beacon = is_channel_radar(ch_info);
+ else {
+ IWL_ERR(priv, "invalid channel switch from %u to %u\n",
+ priv->active_rxon.channel, channel);
+ return -EFAULT;
+ }
+
+ return iwl_send_cmd_sync(priv, &hcmd);
+}
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain,
+ .set_tx_ant = iwl5000_send_tx_ant_config,
};
struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
@@ -1542,10 +1459,10 @@ struct iwl_lib_ops iwl5000_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -1594,10 +1511,10 @@ static struct iwl_lib_ops iwl5150_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -1626,11 +1543,12 @@ static struct iwl_lib_ops iwl5150_lib = {
},
};
-struct iwl_ops iwl5000_ops = {
+static struct iwl_ops iwl5000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
static struct iwl_ops iwl5150_ops = {
@@ -1638,11 +1556,10 @@ static struct iwl_ops iwl5150_ops = {
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
struct iwl_mod_params iwl50_mod_params = {
- .num_of_queues = IWL50_NUM_QUEUES,
- .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -1659,11 +1576,17 @@ struct iwl_cfg iwl5300_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_bg_cfg = {
@@ -1676,11 +1599,17 @@ struct iwl_cfg iwl5100_bg_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_abg_cfg = {
@@ -1693,11 +1622,17 @@ struct iwl_cfg iwl5100_abg_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_agn_cfg = {
@@ -1710,11 +1645,17 @@ struct iwl_cfg iwl5100_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5350_agn_cfg = {
@@ -1727,11 +1668,17 @@ struct iwl_cfg iwl5350_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5150_agn_cfg = {
@@ -1744,24 +1691,31 @@ struct iwl_cfg iwl5150_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
-module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
+module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, S_IRUGO);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
-module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
+module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, S_IRUGO);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
-module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
+module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, S_IRUGO);
MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality");
-module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444);
+module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K,
+ int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series");
-module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index c295b8ee922..32466d38d1a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -44,14 +44,16 @@
#include "iwl-sta.h"
#include "iwl-helpers.h"
#include "iwl-5000-hw.h"
+#include "iwl-6000-hw.h"
+#include "iwl-agn-led.h"
/* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 4
#define IWL6050_UCODE_API_MAX 4
/* Lowest firmware API version supported */
-#define IWL6000_UCODE_API_MIN 1
-#define IWL6050_UCODE_API_MIN 1
+#define IWL6000_UCODE_API_MIN 4
+#define IWL6050_UCODE_API_MIN 4
#define IWL6000_FW_PRE "iwlwifi-6000-"
#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
@@ -71,7 +73,21 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
/* NIC configuration for 6000 series */
static void iwl6000_nic_config(struct iwl_priv *priv)
{
- iwl5000_nic_config(priv);
+ u16 radio_cfg;
+
+ radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+
+ /* write radio config values to register */
+ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX)
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
+ EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
+ EEPROM_RF_CFG_DASH_MSK(radio_cfg));
+
+ /* set CSR_HW_CONFIG_REG for uCode use */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
/* no locking required for register write */
if (priv->cfg->pa_type == IWL_PA_HYBRID) {
@@ -86,8 +102,109 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
/* else do nothing, uCode configured */
}
+static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
+ .min_nrg_cck = 97,
+ .max_nrg_cck = 0, /* not used, set to 0 */
+ .auto_corr_min_ofdm = 80,
+ .auto_corr_min_ofdm_mrc = 128,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 192,
+
+ .auto_corr_max_ofdm = 145,
+ .auto_corr_max_ofdm_mrc = 232,
+ .auto_corr_max_ofdm_x1 = 145,
+ .auto_corr_max_ofdm_mrc_x1 = 232,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 175,
+ .auto_corr_min_cck_mrc = 160,
+ .auto_corr_max_cck_mrc = 310,
+ .nrg_th_cck = 97,
+ .nrg_th_ofdm = 100,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
+};
+
+static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
+{
+ if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+ priv->cfg->num_of_queues =
+ priv->cfg->mod_params->num_of_queues;
+
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+ priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+ priv->hw_params.scd_bc_tbls_size =
+ priv->cfg->num_of_queues *
+ sizeof(struct iwl5000_scd_bc_tbl);
+ priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+ priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+
+ priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
+ priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
+
+ priv->hw_params.max_bsm_size = 0;
+ priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
+ BIT(IEEE80211_BAND_5GHZ);
+ priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
+
+ priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+ priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+
+ if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+ priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+ /* Set initial sensitivity parameters */
+ /* Set initial calibration set */
+ priv->hw_params.sens = &iwl6000_sensitivity;
+ priv->hw_params.calib_init_cfg =
+ BIT(IWL_CALIB_XTAL) |
+ BIT(IWL_CALIB_LO) |
+ BIT(IWL_CALIB_TX_IQ) |
+ BIT(IWL_CALIB_TX_IQ_PERD) |
+ BIT(IWL_CALIB_BASE_BAND);
+
+ return 0;
+}
+
+static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ struct iwl6000_channel_switch_cmd cmd;
+ const struct iwl_channel_info *ch_info;
+ struct iwl_host_cmd hcmd = {
+ .id = REPLY_CHANNEL_SWITCH,
+ .len = sizeof(cmd),
+ .flags = CMD_SIZE_HUGE,
+ .data = &cmd,
+ };
+
+ IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+ priv->active_rxon.channel, channel);
+
+ cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+ cmd.channel = cpu_to_le16(channel);
+ cmd.rxon_flags = priv->active_rxon.flags;
+ cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ if (ch_info)
+ cmd.expect_beacon = is_channel_radar(ch_info);
+ else {
+ IWL_ERR(priv, "invalid channel switch from %u to %u\n",
+ priv->active_rxon.channel, channel);
+ return -EFAULT;
+ }
+
+ return iwl_send_cmd_sync(priv, &hcmd);
+}
+
static struct iwl_lib_ops iwl6000_lib = {
- .set_hw_params = iwl5000_hw_set_hw_params,
+ .set_hw_params = iwl6000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
@@ -106,10 +223,10 @@ static struct iwl_lib_ops iwl6000_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl6000_hw_channel_switch,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl6000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -139,18 +256,27 @@ static struct iwl_lib_ops iwl6000_lib = {
},
};
-static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
+static struct iwl_ops iwl6000_ops = {
+ .ucode = &iwl5000_ucode,
+ .lib = &iwl6000_lib,
+ .hcmd = &iwl5000_hcmd,
+ .utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
+};
+
+static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {
.get_hcmd_size = iwl5000_get_hcmd_size,
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
.rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
.calc_rssi = iwl5000_calc_rssi,
};
-static struct iwl_ops iwl6000_ops = {
+static struct iwl_ops iwl6050_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd,
- .utils = &iwl6000_hcmd_utils,
+ .utils = &iwl6050_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
@@ -165,16 +291,84 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
.pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+};
+
+struct iwl_cfg iwl6000h_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .ucode_api_max = IWL6000_UCODE_API_MAX,
+ .ucode_api_min = IWL6000_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_HYBRID,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+};
+
+struct iwl_cfg iwl6000h_2bg_cfg = {
+ .name = "6000 Series 2x2 BG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .ucode_api_max = IWL6000_UCODE_API_MAX,
+ .ucode_api_min = IWL6000_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_HYBRID,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
};
/*
@@ -188,16 +382,84 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_INTERNAL,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+};
+
+struct iwl_cfg iwl6000i_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .ucode_api_max = IWL6000_UCODE_API_MAX,
+ .ucode_api_min = IWL6000_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_INTERNAL,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+};
+
+struct iwl_cfg iwl6000i_2bg_cfg = {
+ .name = "6000 Series 2x2 BG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .ucode_api_max = IWL6000_UCODE_API_MAX,
+ .ucode_api_min = IWL6000_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_BC,
.valid_rx_ant = ANT_BC,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
.pa_type = IWL_PA_INTERNAL,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -206,18 +468,57 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
+ .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
.pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+};
+
+struct iwl_cfg iwl6050_2abg_cfg = {
+ .name = "6050 Series 2x2 ABG",
+ .fw_name_pre = IWL6050_FW_PRE,
+ .ucode_api_max = IWL6050_UCODE_API_MAX,
+ .ucode_api_min = IWL6050_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6050_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -228,16 +529,26 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
.pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
};
struct iwl_cfg iwl6050_3agn_cfg = {
@@ -246,18 +557,28 @@ struct iwl_cfg iwl6050_3agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6000_ops,
+ .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
.pa_type = IWL_PA_SYSTEM,
- .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
new file mode 100644
index 00000000000..3bccba20f6d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+
+#include "iwl-commands.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-agn-led.h"
+
+/* Send led command */
+static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_LEDS_CMD,
+ .len = sizeof(struct iwl_led_cmd),
+ .data = led_cmd,
+ .flags = CMD_ASYNC,
+ .callback = NULL,
+ };
+ u32 reg;
+
+ reg = iwl_read32(priv, CSR_LED_REG);
+ if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
+ iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+/* Set led register off */
+static int iwl_led_on_reg(struct iwl_priv *priv)
+{
+ IWL_DEBUG_LED(priv, "led on\n");
+ iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+ return 0;
+}
+
+/* Set led register off */
+static int iwl_led_off_reg(struct iwl_priv *priv)
+{
+ IWL_DEBUG_LED(priv, "LED Reg off\n");
+ iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
+ return 0;
+}
+
+const struct iwl_led_ops iwlagn_led_ops = {
+ .cmd = iwl_send_led_cmd,
+ .on = iwl_led_on_reg,
+ .off = iwl_led_off_reg,
+};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
new file mode 100644
index 00000000000..ab55f92a161
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_agn_led_h__
+#define __iwl_agn_led_h__
+
+extern const struct iwl_led_ops iwlagn_led_ops;
+
+#endif /* __iwl_agn_led_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 346dc06fa7b..27d4ece4d46 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -75,104 +75,6 @@ static const u8 ant_toggle_lookup[] = {
/*ANT_ABC -> */ ANT_ABC,
};
-/**
- * struct iwl_rate_scale_data -- tx success history for one rate
- */
-struct iwl_rate_scale_data {
- u64 data; /* bitmap of successful frames */
- s32 success_counter; /* number of frames successful */
- s32 success_ratio; /* per-cent * 128 */
- s32 counter; /* number of frames attempted */
- s32 average_tpt; /* success ratio * expected throughput */
- unsigned long stamp;
-};
-
-/**
- * struct iwl_scale_tbl_info -- tx params and success history for all rates
- *
- * There are two of these in struct iwl_lq_sta,
- * one for "active", and one for "search".
- */
-struct iwl_scale_tbl_info {
- enum iwl_table_type lq_type;
- u8 ant_type;
- u8 is_SGI; /* 1 = short guard interval */
- u8 is_ht40; /* 1 = 40 MHz channel width */
- u8 is_dup; /* 1 = duplicated data streams */
- u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
- u8 max_search; /* maximun number of tables we can search */
- s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
- u32 current_rate; /* rate_n_flags, uCode API format */
- struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
-};
-
-struct iwl_traffic_load {
- unsigned long time_stamp; /* age of the oldest statistics */
- u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
- * slice */
- u32 total; /* total num of packets during the
- * last TID_MAX_TIME_DIFF */
- u8 queue_count; /* number of queues that has
- * been used since the last cleanup */
- u8 head; /* start of the circular buffer */
-};
-
-/**
- * struct iwl_lq_sta -- driver's rate scaling private structure
- *
- * Pointer to this gets passed back and forth between driver and mac80211.
- */
-struct iwl_lq_sta {
- u8 active_tbl; /* index of active table, range 0-1 */
- u8 enable_counter; /* indicates HT mode */
- u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
- u8 search_better_tbl; /* 1: currently trying alternate mode */
- s32 last_tpt;
-
- /* The following determine when to search for a new mode */
- u32 table_count_limit;
- u32 max_failure_limit; /* # failed frames before new search */
- u32 max_success_limit; /* # successful frames before new search */
- u32 table_count;
- u32 total_failed; /* total failed frames, any/all rates */
- u32 total_success; /* total successful frames, any/all rates */
- u64 flush_timer; /* time staying in mode before new search */
-
- u8 action_counter; /* # mode-switch actions tried */
- u8 is_green;
- u8 is_dup;
- enum ieee80211_band band;
- u8 ibss_sta_added;
-
- /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
- u32 supp_rates;
- u16 active_legacy_rate;
- u16 active_siso_rate;
- u16 active_mimo2_rate;
- u16 active_mimo3_rate;
- u16 active_rate_basic;
- s8 max_rate_idx; /* Max rate set by user */
- u8 missed_rate_counter;
-
- struct iwl_link_quality_cmd lq;
- struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
- struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
- u8 tx_agg_tid_en;
-#ifdef CONFIG_MAC80211_DEBUGFS
- struct dentry *rs_sta_dbgfs_scale_table_file;
- struct dentry *rs_sta_dbgfs_stats_table_file;
- struct dentry *rs_sta_dbgfs_rate_scale_data_file;
- struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
- u32 dbg_fixed_rate;
-#endif
- struct iwl_priv *drv;
-
- /* used to be in sta_info */
- int last_txrate_idx;
- /* last tx rate_n_flags */
- u32 last_rate_n_flags;
-};
-
static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sk_buff *skb,
struct ieee80211_sta *sta,
@@ -190,84 +92,78 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
{}
#endif
-/*
- * Expected throughput metrics for following rates:
- * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
- * "G" is the only table that supports CCK (the first 4 rates).
+/**
+ * The following tables contain the expected throughput metrics for all rates
+ *
+ * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
+ *
+ * where invalid entries are zeros.
+ *
+ * CCK rates are only valid in legacy table and will only be used in G
+ * (2.4 GHz) band.
*/
-static s32 expected_tpt_A[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
-};
-
-static s32 expected_tpt_G[IWL_RATE_COUNT] = {
- 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186
-};
-
-static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202
-};
-
-static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
-};
-
-static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
-};
-
-static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
-};
-
-static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257
-};
-
-static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
+static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
};
-static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
+static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 42, 0, 76, 102, 124, 158, 183, 193, 202}, /* Norm */
+ {0, 0, 0, 0, 46, 0, 82, 110, 132, 167, 192, 202, 210}, /* SGI */
+ {0, 0, 0, 0, 48, 0, 93, 135, 176, 251, 319, 351, 381}, /* AGG */
+ {0, 0, 0, 0, 53, 0, 102, 149, 193, 275, 348, 381, 413}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
+static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */
+ {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */
+ {0, 0, 0, 0, 96, 0, 182, 259, 328, 451, 553, 598, 640}, /* AGG */
+ {0, 0, 0, 0, 106, 0, 199, 282, 357, 487, 593, 640, 683}, /* AGG+SGI */
};
-/* Expected throughput metric MIMO3 */
-static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268
+static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250}, /* Norm */
+ {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256}, /* SGI */
+ {0, 0, 0, 0, 92, 0, 175, 250, 317, 436, 534, 578, 619}, /* AGG */
+ {0, 0, 0, 0, 102, 0, 192, 273, 344, 470, 573, 619, 660}, /* AGG+SGI*/
};
-static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273
+static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */
+ {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */
+ {0, 0, 0, 0, 180, 0, 327, 446, 545, 708, 828, 878, 922}, /* AGG */
+ {0, 0, 0, 0, 197, 0, 355, 481, 584, 752, 872, 922, 966}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297
+static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
+ {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
+ {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
+ {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300
+static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */
+ {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */
+ {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */
+ {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */
};
/* mbps, mcs */
const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
- {"1", ""},
- {"2", ""},
- {"5.5", ""},
- {"11", ""},
- {"6", "BPSK 1/2"},
- {"9", "BPSK 1/2"},
- {"12", "QPSK 1/2"},
- {"18", "QPSK 3/4"},
- {"24", "16QAM 1/2"},
- {"36", "16QAM 3/4"},
- {"48", "64QAM 2/3"},
- {"54", "64QAM 3/4"},
- {"60", "64QAM 5/6"}
+ { "1", "BPSK DSSS"},
+ { "2", "QPSK DSSS"},
+ {"5.5", "BPSK CCK"},
+ { "11", "QPSK CCK"},
+ { "6", "BPSK 1/2"},
+ { "9", "BPSK 1/2"},
+ { "12", "QPSK 1/2"},
+ { "18", "QPSK 3/4"},
+ { "24", "16QAM 1/2"},
+ { "36", "16QAM 3/4"},
+ { "48", "64QAM 2/3"},
+ { "54", "64QAM 3/4"},
+ { "60", "64QAM 5/6"},
};
#define MCS_INDEX_PER_STREAM (8)
@@ -418,6 +314,15 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
else if (tid == IWL_AGG_ALL_TID)
for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+ if (priv->cfg->use_rts_for_ht) {
+ /*
+ * switch to RTS/CTS if it is the prefer protection method
+ * for HT traffic
+ */
+ IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
+ priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+ iwlcore_commit_rxon(priv);
+ }
}
static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
@@ -435,7 +340,7 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
* packets.
*/
static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
- int scale_index, s32 tpt, int retries,
+ int scale_index, s32 tpt, int attempts,
int successes)
{
struct iwl_rate_scale_data *window = NULL;
@@ -445,7 +350,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
return -EINVAL;
- /* Select data for current tx bit rate */
+ /* Select window for current tx bit rate */
window = &(windows[scale_index]);
/*
@@ -456,7 +361,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
* subtract "1" from the success counter (this is the main reason
* we keep these bitmaps!).
*/
- while (retries > 0) {
+ while (attempts > 0) {
if (window->counter >= IWL_RATE_MAX_WINDOW) {
/* remove earliest */
@@ -471,17 +376,17 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
/* Increment frames-attempted counter */
window->counter++;
- /* Shift bitmap by one frame (throw away oldest history),
- * OR in "1", and increment "success" if this
- * frame was successful. */
+ /* Shift bitmap by one frame to throw away oldest history */
window->data <<= 1;
+
+ /* Mark the most recent #successes attempts as successful */
if (successes > 0) {
window->success_counter++;
window->data |= 0x1;
successes--;
}
- retries--;
+ attempts--;
}
/* Calculate current success ratio, avoid divide-by-0! */
@@ -662,7 +567,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
* there are no non-GF stations present in the BSS.
*/
static inline u8 rs_use_green(struct ieee80211_sta *sta,
- struct iwl_ht_info *ht_conf)
+ struct iwl_ht_config *ht_conf)
{
return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
!(ht_conf->non_GF_STA_present);
@@ -812,27 +717,45 @@ out:
}
/*
+ * Simple function to compare two rate scale table types
+ */
+static bool table_type_matches(struct iwl_scale_tbl_info *a,
+ struct iwl_scale_tbl_info *b)
+{
+ return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
+ (a->is_SGI == b->is_SGI);
+}
+/*
+ * Static function to get the expected throughput from an iwl_scale_tbl_info
+ * that wraps a NULL pointer check
+ */
+static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
+{
+ if (tbl->expected_tpt)
+ return tbl->expected_tpt[rs_index];
+ return 0;
+}
+
+/*
* mac80211 sends us Tx status
*/
static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
{
- int status;
- u8 retries;
- int rs_index, mac_index, index = 0;
+ int legacy_success;
+ int retries;
+ int rs_index, mac_index, i;
struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_link_quality_cmd *table;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_rate_scale_data *window = NULL;
- struct iwl_rate_scale_data *search_win = NULL;
enum mac80211_rate_control_flags mac_flags;
u32 tx_rate;
struct iwl_scale_tbl_info tbl_type;
- struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
- u8 active_index = 0;
+ struct iwl_scale_tbl_info *curr_tbl, *other_tbl;
s32 tpt = 0;
IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
@@ -841,30 +764,14 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
info->flags & IEEE80211_TX_CTL_NO_ACK)
return;
- /* This packet was aggregated but doesn't carry rate scale info */
+ /* This packet was aggregated but doesn't carry status info */
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
!(info->flags & IEEE80211_TX_STAT_AMPDU))
return;
- if (info->flags & IEEE80211_TX_STAT_AMPDU)
- retries = 0;
- else
- retries = info->status.rates[0].count - 1;
-
- if (retries > 15)
- retries = 15;
-
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added)
- goto out;
-
- table = &lq_sta->lq;
- active_index = lq_sta->active_tbl;
-
- curr_tbl = &(lq_sta->lq_info[active_index]);
- search_tbl = &(lq_sta->lq_info[(1 - active_index)]);
- window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
- search_win = (struct iwl_rate_scale_data *)&(search_tbl->win[0]);
+ return;
/*
* Ignore this Tx frame response if its initial rate doesn't match
@@ -874,6 +781,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
* to check "search" mode, or a prior "search" mode after we've moved
* to a new "search" mode (which might become the new "active" mode).
*/
+ table = &lq_sta->lq;
tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
if (priv->band == IEEE80211_BAND_5GHZ)
@@ -892,7 +800,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
if (priv->band == IEEE80211_BAND_2GHZ)
mac_index += IWL_FIRST_OFDM_RATE;
}
-
+ /* Here we actually compare this rate to the latest LQ command */
if ((mac_index < 0) ||
(tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
(tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
@@ -902,124 +810,106 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
(!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
(rs_index != mac_index)) {
IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate);
- /* the last LQ command could failed so the LQ in ucode not
- * the same in driver sync up
+ /*
+ * Since rates mis-match, the last LQ command may have failed.
+ * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
+ * ... driver.
*/
lq_sta->missed_rate_counter++;
if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
lq_sta->missed_rate_counter = 0;
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
}
- goto out;
+ /* Regardless, ignore this status info for outdated rate */
+ return;
+ } else
+ /* Rate did match, so reset the missed_rate_counter */
+ lq_sta->missed_rate_counter = 0;
+
+ /* Figure out if rate scale algorithm is in active or search table */
+ if (table_type_matches(&tbl_type,
+ &(lq_sta->lq_info[lq_sta->active_tbl]))) {
+ curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ } else if (table_type_matches(&tbl_type,
+ &lq_sta->lq_info[1 - lq_sta->active_tbl])) {
+ curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ } else {
+ IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
+ return;
}
+ window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
- lq_sta->missed_rate_counter = 0;
- /* Update frame history window with "failure" for each Tx retry. */
- while (retries) {
- /* Look up the rate and other info used for each tx attempt.
- * Each tx attempt steps one entry deeper in the rate table. */
- tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
- rs_get_tbl_info_from_mcs(tx_rate, priv->band,
- &tbl_type, &rs_index);
-
- /* If type matches "search" table,
- * add failure to "search" history */
- if ((tbl_type.lq_type == search_tbl->lq_type) &&
- (tbl_type.ant_type == search_tbl->ant_type) &&
- (tbl_type.is_SGI == search_tbl->is_SGI)) {
- if (search_tbl->expected_tpt)
- tpt = search_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- rs_collect_tx_data(search_win, rs_index, tpt, 1, 0);
-
- /* Else if type matches "current/active" table,
- * add failure to "current/active" history */
- } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
- (tbl_type.ant_type == curr_tbl->ant_type) &&
- (tbl_type.is_SGI == curr_tbl->is_SGI)) {
- if (curr_tbl->expected_tpt)
- tpt = curr_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- rs_collect_tx_data(window, rs_index, tpt, 1, 0);
+ /*
+ * Updating the frame history depends on whether packets were
+ * aggregated.
+ *
+ * For aggregation, all packets were transmitted at the same rate, the
+ * first index into rate scale table.
+ */
+ if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+ tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
+ rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
+ &rs_index);
+ tpt = get_expected_tpt(curr_tbl, rs_index);
+ rs_collect_tx_data(window, rs_index, tpt,
+ info->status.ampdu_ack_len,
+ info->status.ampdu_ack_map);
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->stay_in_tbl) {
+ lq_sta->total_success += info->status.ampdu_ack_map;
+ lq_sta->total_failed += (info->status.ampdu_ack_len -
+ info->status.ampdu_ack_map);
}
-
- /* If not searching for a new mode, increment failed counter
- * ... this helps determine when to start searching again */
- if (lq_sta->stay_in_tbl)
- lq_sta->total_failed++;
- --retries;
- index++;
-
- }
-
+ } else {
/*
- * Find (by rate) the history window to update with final Tx attempt;
- * if Tx was successful first try, use original rate,
- * else look up the rate that was, finally, successful.
+ * For legacy, update frame history with for each Tx retry.
*/
- tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
- lq_sta->last_rate_n_flags = tx_rate;
- rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
-
- /* Update frame history window with "success" if Tx got ACKed ... */
- status = !!(info->flags & IEEE80211_TX_STAT_ACK);
-
- /* If type matches "search" table,
- * add final tx status to "search" history */
- if ((tbl_type.lq_type == search_tbl->lq_type) &&
- (tbl_type.ant_type == search_tbl->ant_type) &&
- (tbl_type.is_SGI == search_tbl->is_SGI)) {
- if (search_tbl->expected_tpt)
- tpt = search_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- if (info->flags & IEEE80211_TX_STAT_AMPDU)
- rs_collect_tx_data(search_win, rs_index, tpt,
- info->status.ampdu_ack_len,
- info->status.ampdu_ack_map);
- else
- rs_collect_tx_data(search_win, rs_index, tpt,
- 1, status);
- /* Else if type matches "current/active" table,
- * add final tx status to "current/active" history */
- } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
- (tbl_type.ant_type == curr_tbl->ant_type) &&
- (tbl_type.is_SGI == curr_tbl->is_SGI)) {
- if (curr_tbl->expected_tpt)
- tpt = curr_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- if (info->flags & IEEE80211_TX_STAT_AMPDU)
- rs_collect_tx_data(window, rs_index, tpt,
- info->status.ampdu_ack_len,
- info->status.ampdu_ack_map);
- else
- rs_collect_tx_data(window, rs_index, tpt,
- 1, status);
- }
+ retries = info->status.rates[0].count - 1;
+ /* HW doesn't send more than 15 retries */
+ retries = min(retries, 15);
+
+ /* The last transmission may have been successful */
+ legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+ /* Collect data for each rate used during failed TX attempts */
+ for (i = 0; i <= retries; ++i) {
+ tx_rate = le32_to_cpu(table->rs_table[i].rate_n_flags);
+ rs_get_tbl_info_from_mcs(tx_rate, priv->band,
+ &tbl_type, &rs_index);
+ /*
+ * Only collect stats if retried rate is in the same RS
+ * table as active/search.
+ */
+ if (table_type_matches(&tbl_type, curr_tbl))
+ tpt = get_expected_tpt(curr_tbl, rs_index);
+ else if (table_type_matches(&tbl_type, other_tbl))
+ tpt = get_expected_tpt(other_tbl, rs_index);
+ else
+ continue;
- /* If not searching for new mode, increment success/failed counter
- * ... these help determine when to start searching again */
- if (lq_sta->stay_in_tbl) {
- if (info->flags & IEEE80211_TX_STAT_AMPDU) {
- lq_sta->total_success += info->status.ampdu_ack_map;
- lq_sta->total_failed +=
- (info->status.ampdu_ack_len - info->status.ampdu_ack_map);
- } else {
- if (status)
- lq_sta->total_success++;
+ /* Constants mean 1 transmission, 0 successes */
+ if (i < retries)
+ rs_collect_tx_data(window, rs_index, tpt, 1,
+ 0);
else
- lq_sta->total_failed++;
+ rs_collect_tx_data(window, rs_index, tpt, 1,
+ legacy_success);
+ }
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->stay_in_tbl) {
+ lq_sta->total_success += legacy_success;
+ lq_sta->total_failed += retries + (1 - legacy_success);
}
}
+ /* The last TX rate is cached in lq_sta; it's set in if/else above */
+ lq_sta->last_rate_n_flags = tx_rate;
/* See if there's a better rate or modulation mode to try. */
if (sta && sta->supp_rates[sband->band])
rs_rate_scale_perform(priv, skb, sta, lq_sta);
-out:
- return;
}
/*
@@ -1057,43 +947,45 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl)
{
+ /* Used to choose among HT tables */
+ s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+
+ /* Check for invalid LQ type */
+ if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
+ tbl->expected_tpt = expected_tpt_legacy;
+ return;
+ }
+
+ /* Legacy rates have only one table */
if (is_legacy(tbl->lq_type)) {
- if (!is_a_band(tbl->lq_type))
- tbl->expected_tpt = expected_tpt_G;
- else
- tbl->expected_tpt = expected_tpt_A;
- } else if (is_siso(tbl->lq_type)) {
- if (tbl->is_ht40 && !lq_sta->is_dup)
- if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_siso40MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_siso40MHz;
- else if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_siso20MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_siso20MHz;
- } else if (is_mimo2(tbl->lq_type)) {
- if (tbl->is_ht40 && !lq_sta->is_dup)
- if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo2_40MHz;
- else if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo2_20MHz;
- } else if (is_mimo3(tbl->lq_type)) {
- if (tbl->is_ht40 && !lq_sta->is_dup)
- if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo3_40MHz;
- else if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo3_20MHz;
- } else
- tbl->expected_tpt = expected_tpt_G;
+ tbl->expected_tpt = expected_tpt_legacy;
+ return;
+ }
+
+ /* Choose among many HT tables depending on number of streams
+ * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation
+ * status */
+ if (is_siso(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+ ht_tbl_pointer = expected_tpt_siso20MHz;
+ else if (is_siso(tbl->lq_type))
+ ht_tbl_pointer = expected_tpt_siso40MHz;
+ else if (is_mimo2(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+ ht_tbl_pointer = expected_tpt_mimo2_20MHz;
+ else if (is_mimo2(tbl->lq_type))
+ ht_tbl_pointer = expected_tpt_mimo2_40MHz;
+ else if (is_mimo3(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+ ht_tbl_pointer = expected_tpt_mimo3_20MHz;
+ else /* if (is_mimo3(tbl->lq_type)) <-- must be true */
+ ht_tbl_pointer = expected_tpt_mimo3_40MHz;
+
+ if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */
+ tbl->expected_tpt = ht_tbl_pointer[0];
+ else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */
+ tbl->expected_tpt = ht_tbl_pointer[1];
+ else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */
+ tbl->expected_tpt = ht_tbl_pointer[2];
+ else /* AGG+SGI */
+ tbl->expected_tpt = ht_tbl_pointer[3];
}
/*
@@ -2068,6 +1960,14 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
tid = rs_tl_add_packet(lq_sta, hdr);
+ if ((tid != MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) {
+ tid_data = &priv->stations[lq_sta->lq.sta_id].tid[tid];
+ if (tid_data->agg.state == IWL_AGG_OFF)
+ lq_sta->is_agg = 0;
+ else
+ lq_sta->is_agg = 1;
+ } else
+ lq_sta->is_agg = 0;
/*
* Select rate-scale / modulation-mode table to work with in
@@ -2168,10 +2068,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
goto out;
}
-
/* Else we have enough samples; calculate estimate of
* actual average throughput */
+ /* Sanity-check TPT calculations */
BUG_ON(window->average_tpt != ((window->success_ratio *
tbl->expected_tpt[index] + 64) / 128));
@@ -2575,19 +2475,17 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
gfp_t gfp)
{
struct iwl_lq_sta *lq_sta;
+ struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
struct iwl_priv *priv;
int i, j;
priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE(priv, "create station rate scale window\n");
- lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp);
+ lq_sta = &sta_priv->lq_sta;
- if (lq_sta == NULL)
- return NULL;
lq_sta->lq.sta_id = 0xff;
-
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
@@ -2681,6 +2579,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
if (sband->band == IEEE80211_BAND_5GHZ)
lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+ lq_sta->is_agg = 0;
rs_initialize_lq(priv, conf, sta, lq_sta);
}
@@ -2799,7 +2698,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
repeat_rate--;
}
- lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX;
+ lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
lq_cmd->agg_params.agg_time_limit =
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
@@ -2818,11 +2717,9 @@ static void rs_free(void *priv_rate)
static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
void *priv_sta)
{
- struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_priv *priv __maybe_unused = priv_r;
IWL_DEBUG_RATE(priv, "enter\n");
- kfree(lq_sta);
IWL_DEBUG_RATE(priv, "leave\n");
}
@@ -2933,8 +2830,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
desc += sprintf(buff+desc, " %s",
(tbl->is_ht40) ? "40MHz" : "20MHz");
- desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "",
- (lq_sta->is_green) ? "GF enabled" : "");
+ desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "",
+ (lq_sta->is_green) ? "GF enabled" : "",
+ (lq_sta->is_agg) ? "AGG on" : "");
}
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
lq_sta->last_rate_n_flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 9fac530cfb7..affc0c5a2f2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -54,6 +54,7 @@ struct iwl3945_rate_info {
u8 prev_table_rs; /* prev in rate table cmd */
};
+
/*
* These serve as indexes into
* struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
@@ -335,6 +336,106 @@ struct iwl_rate_mcs_info {
char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
};
+/**
+ * struct iwl_rate_scale_data -- tx success history for one rate
+ */
+struct iwl_rate_scale_data {
+ u64 data; /* bitmap of successful frames */
+ s32 success_counter; /* number of frames successful */
+ s32 success_ratio; /* per-cent * 128 */
+ s32 counter; /* number of frames attempted */
+ s32 average_tpt; /* success ratio * expected throughput */
+ unsigned long stamp;
+};
+
+/**
+ * struct iwl_scale_tbl_info -- tx params and success history for all rates
+ *
+ * There are two of these in struct iwl_lq_sta,
+ * one for "active", and one for "search".
+ */
+struct iwl_scale_tbl_info {
+ enum iwl_table_type lq_type;
+ u8 ant_type;
+ u8 is_SGI; /* 1 = short guard interval */
+ u8 is_ht40; /* 1 = 40 MHz channel width */
+ u8 is_dup; /* 1 = duplicated data streams */
+ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+ u8 max_search; /* maximun number of tables we can search */
+ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
+ u32 current_rate; /* rate_n_flags, uCode API format */
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
+};
+
+struct iwl_traffic_load {
+ unsigned long time_stamp; /* age of the oldest statistics */
+ u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
+ * slice */
+ u32 total; /* total num of packets during the
+ * last TID_MAX_TIME_DIFF */
+ u8 queue_count; /* number of queues that has
+ * been used since the last cleanup */
+ u8 head; /* start of the circular buffer */
+};
+
+/**
+ * struct iwl_lq_sta -- driver's rate scaling private structure
+ *
+ * Pointer to this gets passed back and forth between driver and mac80211.
+ */
+struct iwl_lq_sta {
+ u8 active_tbl; /* index of active table, range 0-1 */
+ u8 enable_counter; /* indicates HT mode */
+ u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
+ u8 search_better_tbl; /* 1: currently trying alternate mode */
+ s32 last_tpt;
+
+ /* The following determine when to search for a new mode */
+ u32 table_count_limit;
+ u32 max_failure_limit; /* # failed frames before new search */
+ u32 max_success_limit; /* # successful frames before new search */
+ u32 table_count;
+ u32 total_failed; /* total failed frames, any/all rates */
+ u32 total_success; /* total successful frames, any/all rates */
+ u64 flush_timer; /* time staying in mode before new search */
+
+ u8 action_counter; /* # mode-switch actions tried */
+ u8 is_green;
+ u8 is_dup;
+ enum ieee80211_band band;
+ u8 ibss_sta_added;
+
+ /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
+ u32 supp_rates;
+ u16 active_legacy_rate;
+ u16 active_siso_rate;
+ u16 active_mimo2_rate;
+ u16 active_mimo3_rate;
+ u16 active_rate_basic;
+ s8 max_rate_idx; /* Max rate set by user */
+ u8 missed_rate_counter;
+
+ struct iwl_link_quality_cmd lq;
+ struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+ struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
+ u8 tx_agg_tid_en;
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *rs_sta_dbgfs_scale_table_file;
+ struct dentry *rs_sta_dbgfs_stats_table_file;
+ struct dentry *rs_sta_dbgfs_rate_scale_data_file;
+ struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
+ u32 dbg_fixed_rate;
+#endif
+ struct iwl_priv *drv;
+
+ /* used to be in sta_info */
+ int last_txrate_idx;
+ /* last tx rate_n_flags */
+ u32 last_rate_n_flags;
+ /* packets destined for this STA are aggregated */
+ u8 is_agg;
+};
+
static inline u8 num_of_ant(u8 mask)
{
return !!((mask) & ANT_A) +
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 9b5ea8ba721..fa1672e99e4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -115,9 +115,6 @@ int iwl_commit_rxon(struct iwl_priv *priv)
/* always get timestamp with Rx frame */
priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
- /* allow CTS-to-self if possible. this is relevant only for
- * 5000, but will not damage 4965 */
- priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
ret = iwl_check_rxon_cmd(priv);
if (ret) {
@@ -217,6 +214,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
"Could not send WEP static key.\n");
}
+ /*
+ * allow CTS-to-self if possible for new association.
+ * this is relevant only for 5000 series and up,
+ * but will not damage 4965
+ */
+ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+
/* Apply the new configuration
* RXON assoc doesn't clear the station table in uCode,
*/
@@ -520,7 +524,7 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
static void iwl_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_alive_resp *palive;
struct delayed_work *pwork;
@@ -606,7 +610,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl4965_beacon_notif *beacon =
(struct iwl4965_beacon_notif *)pkt->u.raw;
u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
@@ -630,7 +634,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
@@ -765,7 +769,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
/* calculate total frames need to be restock after handling RX */
- total_empty = r - priv->rxq.write_actual;
+ total_empty = r - rxq->write_actual;
if (total_empty < 0)
total_empty += RX_QUEUE_SIZE;
@@ -782,10 +786,13 @@ void iwl_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL;
- pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
- pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ pci_unmap_page(priv->pci_dev, rxb->page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ pkt = rxb_addr(rxb);
+
+ trace_iwlwifi_dev_rx(priv, pkt,
+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
@@ -807,8 +814,8 @@ void iwl_rx_handle(struct iwl_priv *priv)
if (priv->rx_handlers[pkt->hdr.cmd]) {
IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r,
i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
- priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
} else {
/* No handling needed */
IWL_DEBUG_RX(priv,
@@ -817,35 +824,45 @@ void iwl_rx_handle(struct iwl_priv *priv)
pkt->hdr.cmd);
}
+ /*
+ * XXX: After here, we should always check rxb->page
+ * against NULL before touching it or its virtual
+ * memory (pkt). Because some rx_handler might have
+ * already taken or freed the pages.
+ */
+
if (reclaim) {
- /* Invoke any callbacks, transfer the skb to caller, and
- * fire off the (possibly) blocking iwl_send_cmd()
+ /* Invoke any callbacks, transfer the buffer to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
* as we reclaim the driver command queue */
- if (rxb && rxb->skb)
+ if (rxb->page)
iwl_tx_cmd_complete(priv, rxb);
else
IWL_WARN(priv, "Claim null rxb?\n");
}
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
+ /* Reuse the page if possible. For notification packets and
+ * SKBs that fail to Rx correctly, add them back into the
+ * rx_free list for reuse later. */
spin_lock_irqsave(&rxq->lock, flags);
- list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ if (rxb->page != NULL) {
+ rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page,
+ 0, PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ } else
+ list_add_tail(&rxb->list, &rxq->rx_used);
+
spin_unlock_irqrestore(&rxq->lock, flags);
+
i = (i + 1) & RX_QUEUE_MASK;
/* If there are a lot of unused frames,
* restock the Rx queue so ucode wont assert. */
if (fill_rx) {
count++;
if (count >= 8) {
- priv->rxq.read = i;
+ rxq->read = i;
iwl_rx_replenish_now(priv);
count = 0;
}
@@ -853,7 +870,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
}
/* Backtrack one entry */
- priv->rxq.read = i;
+ rxq->read = i;
if (fill_rx)
iwl_rx_replenish_now(priv);
else
@@ -900,6 +917,8 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
}
#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
* atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after
@@ -921,8 +940,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1012,6 +1029,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
iwl_rx_handle(priv);
priv->isr_stats.rx++;
+ iwl_leds_background(priv);
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
}
@@ -1049,7 +1067,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
}
#endif
- spin_unlock_irqrestore(&priv->lock, flags);
}
/* tasklet for iwlagn interrupt */
@@ -1079,6 +1096,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta, inta_mask);
}
#endif
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* saved interrupt in inta variable now we can reset priv->inta */
priv->inta = 0;
@@ -1094,8 +1114,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1213,6 +1231,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_INT_PERIODIC_ENA);
priv->isr_stats.rx++;
+ iwl_leds_background(priv);
}
if (inta & CSR_INT_BIT_FH_TX) {
@@ -1235,14 +1254,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta & ~priv->inta_mask);
}
-
/* Re-enable all interrupts */
/* only Re-enable if diabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
iwl_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
}
@@ -1606,6 +1621,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+ trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
+ blink1, blink2, ilink1, ilink2);
+
IWL_ERR(priv, "Desc Time "
"data1 data2 line\n");
IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
@@ -1654,12 +1672,14 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
ptr += sizeof(u32);
if (mode == 0) {
/* data, ev */
+ trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
time, data, ev);
+ trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
}
}
}
@@ -1758,6 +1778,10 @@ static void iwl_alive_start(struct iwl_priv *priv)
priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+ /* Configure Tx antenna selection based on H/W config */
+ if (priv->cfg->ops->hcmd->set_tx_ant)
+ priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant);
+
if (iwl_is_associated(priv)) {
struct iwl_rxon_cmd *active_rxon =
(struct iwl_rxon_cmd *)&priv->active_rxon;
@@ -1785,7 +1809,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
/* At this point, the NIC is initialized and operational */
iwl_rf_kill_ct_config(priv);
- iwl_leds_register(priv);
+ iwl_leds_init(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
set_bit(STATUS_READY, &priv->status);
@@ -1823,8 +1847,6 @@ static void __iwl_down(struct iwl_priv *priv)
if (!exit_pending)
set_bit(STATUS_EXIT_PENDING, &priv->status);
- iwl_leds_unregister(priv);
-
iwl_clear_stations_table(priv);
/* Unblock any waiting calls */
@@ -1885,11 +1907,9 @@ static void __iwl_down(struct iwl_priv *priv)
udelay(5);
- /* FIXME: apm_ops.suspend(priv) */
- if (exit_pending)
- priv->cfg->ops->lib->apm_ops.stop(priv);
- else
- priv->cfg->ops->lib->apm_ops.reset(priv);
+ /* Stop the device, and put it in low power state */
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+
exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@@ -2276,6 +2296,69 @@ void iwl_post_associate(struct iwl_priv *priv)
#define UCODE_READY_TIMEOUT (4 * HZ)
+/*
+ * Not a mac80211 entry point function, but it fits in with all the
+ * other mac80211 functions grouped here.
+ */
+static int iwl_setup_mac(struct iwl_priv *priv)
+{
+ int ret;
+ struct ieee80211_hw *hw = priv->hw;
+ hw->rate_control_algorithm = "iwl-agn-rs";
+
+ /* Tell mac80211 our characteristics */
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM |
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_SPECTRUM_MGMT;
+
+ if (!priv->cfg->broken_powersave)
+ hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+
+ hw->sta_data_size = sizeof(struct iwl_station_priv);
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
+ hw->wiphy->custom_regulatory = true;
+
+ /* Firmware does not support this */
+ hw->wiphy->disable_beacon_hints = true;
+
+ /*
+ * For now, disable PS by default because it affects
+ * RX performance significantly.
+ */
+ hw->wiphy->ps_default = false;
+
+ hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+ /* we create the 802.11 header and a zero-length SSID element */
+ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
+
+ /* Default value; 4 EDCA QOS priorities */
+ hw->queues = 4;
+
+ hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+ if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+ priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &priv->bands[IEEE80211_BAND_2GHZ];
+ if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+ priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &priv->bands[IEEE80211_BAND_5GHZ];
+
+ ret = ieee80211_register_hw(priv->hw);
+ if (ret) {
+ IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+ return ret;
+ }
+ priv->mac80211_registered = 1;
+
+ return 0;
+}
+
+
static int iwl_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
@@ -2323,6 +2406,8 @@ static int iwl_mac_start(struct ieee80211_hw *hw)
}
}
+ iwl_led_start(priv);
+
out:
priv->is_open = 1;
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2794,6 +2879,40 @@ static ssize_t show_statistics(struct device *d,
static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+static ssize_t show_rts_ht_protection(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ return sprintf(buf, "%s\n",
+ priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
+}
+
+static ssize_t store_rts_ht_protection(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ IWL_INFO(priv, "Input is not in decimal form.\n");
+ else {
+ if (!iwl_is_associated(priv))
+ priv->cfg->use_rts_for_ht = val ? true : false;
+ else
+ IWL_ERR(priv, "Sta associated with AP - "
+ "Change protection mechanism is not allowed\n");
+ ret = count;
+ }
+ return ret;
+}
+
+static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
+ show_rts_ht_protection, store_rts_ht_protection);
+
/*****************************************************************************
*
@@ -2850,6 +2969,7 @@ static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_statistics.attr,
&dev_attr_temperature.attr,
&dev_attr_tx_power.attr,
+ &dev_attr_rts_ht_protection.attr,
#ifdef CONFIG_IWLWIFI_DEBUG
&dev_attr_debug_level.attr,
#endif
@@ -3136,6 +3256,15 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_down(priv);
}
+ /*
+ * Make sure device is reset to low power before unloading driver.
+ * This may be redundant with iwl_down(), but there are paths to
+ * run iwl_down() without calling apm_ops.stop(), and there are
+ * paths to avoid running iwl_down() at all before leaving driver.
+ * This (inexpensive) call *makes sure* device is reset.
+ */
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+
iwl_tt_exit(priv);
/* make sure we flush any pending irq or
@@ -3215,20 +3344,51 @@ static struct pci_device_id iwl_hw_card_ids[] = {
/* 5150 Wifi/WiMax */
{IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
-/* 6000/6050 Series */
- {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)},
- {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)},
- {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)},
- {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)},
- {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)},
- {IWL_PCI_DEVICE(0x0089, PCI_ANY_ID, iwl6050_2agn_cfg)},
+
+/* 6x00 Series */
+ {IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)},
+
+ {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
+
+/* 6x50 WiFi/WiMax Series */
+ {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
+
/* 1000 Series WiFi */
- {IWL_PCI_DEVICE(0x0083, PCI_ANY_ID, iwl1000_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0084, PCI_ANY_ID, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1225, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1325, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1215, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1315, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1206, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1306, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1226, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)},
#endif /* CONFIG_IWL5000 */
{0}
@@ -3283,9 +3443,9 @@ module_exit(iwl_exit);
module_init(iwl_init);
#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug50, iwl_debug_level, uint, 0444);
+module_param_named(debug50, iwl_debug_level, uint, S_IRUGO);
MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
-module_param_named(debug, iwl_debug_level, uint, 0644);
+module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index c4b565a2de9..1f801eb9fbf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -447,11 +447,11 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
cpu_to_le16((u16)data->nrg_th_ofdm);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
- cpu_to_le16(190);
+ cpu_to_le16(data->barker_corr_th_min);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
- cpu_to_le16(390);
+ cpu_to_le16(data->barker_corr_th_min_mrc);
cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
- cpu_to_le16(62);
+ cpu_to_le16(data->nrg_th_cca);
IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
@@ -516,7 +516,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
data->nrg_silence_rssi[i] = 0;
- data->auto_corr_ofdm = 90;
+ data->auto_corr_ofdm = ranges->auto_corr_min_ofdm;
data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc;
data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1;
data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1;
@@ -524,6 +524,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
data->nrg_th_cck = ranges->nrg_th_cck;
data->nrg_th_ofdm = ranges->nrg_th_ofdm;
+ data->barker_corr_th_min = ranges->barker_corr_th_min;
+ data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc;
+ data->nrg_th_cca = ranges->nrg_th_cca;
data->last_bad_plcp_cnt_ofdm = 0;
data->last_fa_cnt_ofdm = 0;
@@ -643,6 +646,15 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_sensitivity_calibration);
+static inline u8 find_first_chain(u8 mask)
+{
+ if (mask & ANT_A)
+ return CHAIN_A;
+ if (mask & ANT_B)
+ return CHAIN_B;
+ return CHAIN_C;
+}
+
/*
* Accumulate 20 beacons of signal and noise statistics for each of
* 3 receivers/antennas/rx-chains, then figure out:
@@ -675,14 +687,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
u8 num_tx_chains;
unsigned long flags;
struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+ u8 first_chain;
if (priv->disable_chain_noise_cal)
return;
data = &(priv->chain_noise_data);
- /* Accumulate just the first 20 beacons after the first association,
- * then we're done forever. */
+ /*
+ * Accumulate just the first "chain_noise_num_beacons" after
+ * the first association, then we're done forever.
+ */
if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
if (data->state == IWL_CHAIN_NOISE_ALIVE)
IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n");
@@ -710,7 +725,10 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
return;
}
- /* Accumulate beacon statistics values across 20 beacons */
+ /*
+ * Accumulate beacon statistics values across
+ * "chain_noise_num_beacons"
+ */
chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
IN_BAND_FILTER;
chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
@@ -741,16 +759,19 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n",
chain_noise_a, chain_noise_b, chain_noise_c);
- /* If this is the 20th beacon, determine:
+ /* If this is the "chain_noise_num_beacons", determine:
* 1) Disconnected antennas (using signal strengths)
* 2) Differential gain (using silence noise) to balance receivers */
- if (data->beacon_count != CAL_NUM_OF_BEACONS)
+ if (data->beacon_count != priv->cfg->chain_noise_num_beacons)
return;
/* Analyze signal for disconnected antenna */
- average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
- average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
- average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
+ average_sig[0] =
+ (data->chain_signal_a) / priv->cfg->chain_noise_num_beacons;
+ average_sig[1] =
+ (data->chain_signal_b) / priv->cfg->chain_noise_num_beacons;
+ average_sig[2] =
+ (data->chain_signal_c) / priv->cfg->chain_noise_num_beacons;
if (average_sig[0] >= average_sig[1]) {
max_average_sig = average_sig[0];
@@ -803,13 +824,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
/* there is a Tx antenna connected */
break;
if (num_tx_chains == priv->hw_params.tx_chains_num &&
- data->disconn_array[i]) {
- /* This is the last TX antenna and is also
- * disconnected connect it anyway */
- data->disconn_array[i] = 0;
- active_chains |= ant_msk;
- IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - "
- "declare %d as connected\n", i);
+ data->disconn_array[i]) {
+ /*
+ * If all chains are disconnected
+ * connect the first valid tx chain
+ */
+ first_chain =
+ find_first_chain(priv->cfg->valid_tx_ant);
+ data->disconn_array[first_chain] = 0;
+ active_chains |= BIT(first_chain);
+ IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n",
+ first_chain);
break;
}
}
@@ -820,9 +845,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
active_chains);
/* Analyze noise for rx balance */
- average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
- average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
- average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+ average_noise[0] =
+ ((data->chain_noise_a) / priv->cfg->chain_noise_num_beacons);
+ average_noise[1] =
+ ((data->chain_noise_b) / priv->cfg->chain_noise_num_beacons);
+ average_noise[2] =
+ ((data->chain_noise_c) / priv->cfg->chain_noise_num_beacons);
for (i = 0; i < NUM_RX_CHAINS; i++) {
if (!(data->disconn_array[i]) &&
@@ -843,7 +871,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
if (priv->cfg->ops->utils->gain_computation)
priv->cfg->ops->utils->gain_computation(priv, average_noise,
- min_average_noise_antenna_i, min_average_noise);
+ min_average_noise_antenna_i, min_average_noise,
+ find_first_chain(priv->cfg->valid_rx_ant));
/* Some power changes may have been made during the calibration.
* Update and commit the RXON
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 4afaf773aea..954bad60355 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -109,11 +109,12 @@ enum {
REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
/* WiMAX coexistence */
- COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */
+ COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */
COEX_MEDIUM_NOTIFICATION = 0x5b,
COEX_EVENT_CMD = 0x5c,
/* Calibration */
+ TEMPERATURE_NOTIFICATION = 0x62,
CALIBRATION_CFG_CMD = 0x65,
CALIBRATION_RES_NOTIFICATION = 0x66,
CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
@@ -148,7 +149,7 @@ enum {
QUIET_NOTIFICATION = 0x96, /* not used */
REPLY_TX_PWR_TABLE_CMD = 0x97,
REPLY_TX_POWER_DBM_CMD_V1 = 0x98, /* old version of API */
- TX_ANT_CONFIGURATION_CMD = 0x98, /* not used */
+ TX_ANT_CONFIGURATION_CMD = 0x98,
MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */
/* Bluetooth device coexistence config command */
@@ -353,6 +354,9 @@ struct iwl3945_power_per_rate {
#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32
#define POWER_TABLE_CCK_ENTRY 32
+#define IWL_PWR_NUM_HT_OFDM_ENTRIES 24
+#define IWL_PWR_CCK_ENTRIES 2
+
/**
* union iwl4965_tx_power_dual_stream
*
@@ -411,6 +415,16 @@ struct iwl5000_tx_power_dbm_cmd {
u8 reserved;
} __attribute__ ((packed));
+/**
+ * Command TX_ANT_CONFIGURATION_CMD = 0x98
+ * This command is used to configure valid Tx antenna.
+ * By default uCode concludes the valid antenna according to the radio flavor.
+ * This command enables the driver to override/modify this conclusion.
+ */
+struct iwl_tx_ant_config_cmd {
+ __le32 valid;
+} __attribute__ ((packed));
+
/******************************************************************************
* (0a)
* Alive and Error Commands & Responses:
@@ -793,7 +807,7 @@ struct iwl3945_channel_switch_cmd {
struct iwl3945_power_per_rate power[IWL_MAX_RATES];
} __attribute__ ((packed));
-struct iwl_channel_switch_cmd {
+struct iwl4965_channel_switch_cmd {
u8 band;
u8 expect_beacon;
__le16 channel;
@@ -803,6 +817,48 @@ struct iwl_channel_switch_cmd {
struct iwl4965_tx_power_db tx_power;
} __attribute__ ((packed));
+/**
+ * struct iwl5000_channel_switch_cmd
+ * @band: 0- 5.2GHz, 1- 2.4GHz
+ * @expect_beacon: 0- resume transmits after channel switch
+ * 1- wait for beacon to resume transmits
+ * @channel: new channel number
+ * @rxon_flags: Rx on flags
+ * @rxon_filter_flags: filtering parameters
+ * @switch_time: switch time in extended beacon format
+ * @reserved: reserved bytes
+ */
+struct iwl5000_channel_switch_cmd {
+ u8 band;
+ u8 expect_beacon;
+ __le16 channel;
+ __le32 rxon_flags;
+ __le32 rxon_filter_flags;
+ __le32 switch_time;
+ __le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
+} __attribute__ ((packed));
+
+/**
+ * struct iwl6000_channel_switch_cmd
+ * @band: 0- 5.2GHz, 1- 2.4GHz
+ * @expect_beacon: 0- resume transmits after channel switch
+ * 1- wait for beacon to resume transmits
+ * @channel: new channel number
+ * @rxon_flags: Rx on flags
+ * @rxon_filter_flags: filtering parameters
+ * @switch_time: switch time in extended beacon format
+ * @reserved: reserved bytes
+ */
+struct iwl6000_channel_switch_cmd {
+ u8 band;
+ u8 expect_beacon;
+ __le16 channel;
+ __le32 rxon_flags;
+ __le32 rxon_filter_flags;
+ __le32 switch_time;
+ __le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
+} __attribute__ ((packed));
+
/*
* CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
*/
@@ -2162,6 +2218,19 @@ struct iwl_link_quality_cmd {
__le32 reserved2;
} __attribute__ ((packed));
+#define BT_COEX_DISABLE (0x0)
+#define BT_COEX_MODE_2W (0x1)
+#define BT_COEX_MODE_3W (0x2)
+#define BT_COEX_MODE_4W (0x3)
+
+#define BT_LEAD_TIME_MIN (0x0)
+#define BT_LEAD_TIME_DEF (0x1E)
+#define BT_LEAD_TIME_MAX (0xFF)
+
+#define BT_MAX_KILL_MIN (0x1)
+#define BT_MAX_KILL_DEF (0x5)
+#define BT_MAX_KILL_MAX (0xFF)
+
/*
* REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
*
@@ -3237,12 +3306,6 @@ struct iwl_missed_beacon_notif {
* Lower values mean higher energy; this means making sure that the value
* in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
*
- * Driver should set the following entries to fixed values:
- *
- * HD_MIN_ENERGY_OFDM_DET_INDEX 100
- * HD_BARKER_CORR_TH_ADD_MIN_INDEX 190
- * HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390
- * HD_OFDM_ENERGY_TH_IN_INDEX 62
*/
/*
@@ -3495,6 +3558,16 @@ struct iwl_wimax_coex_cmd {
*****************************************************************************/
struct iwl_rx_packet {
+ /*
+ * The first 4 bytes of the RX frame header contain both the RX frame
+ * size and some flags.
+ * Bit fields:
+ * 31: flag flush RB request
+ * 30: flag ignore TC (terminal counter) request
+ * 29: flag fast IRQ request
+ * 28-14: Reserved
+ * 13-00: RX frame size
+ */
__le32 len_n_flags;
struct iwl_cmd_header hdr;
union {
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 484d5c1a731..d2b56baf98f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -604,11 +604,27 @@ void iwlcore_free_geos(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_free_geos);
+/*
+ * iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this
+ * function.
+ */
+void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+ __le32 *tx_flags)
+{
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ *tx_flags |= TX_CMD_FLG_RTS_MSK;
+ *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ *tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+}
+EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
+
static bool is_single_rx_stream(struct iwl_priv *priv)
{
return !priv->current_ht_config.is_ht ||
- ((priv->current_ht_config.mcs.rx_mask[1] == 0) &&
- (priv->current_ht_config.mcs.rx_mask[2] == 0));
+ priv->current_ht_config.single_chain_sufficient;
}
static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -634,10 +650,9 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf)
{
- struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
- if ((!iwl_ht_conf->is_ht) ||
- (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ))
+ if (!ht_conf->is_ht || !ht_conf->is_40mhz)
return 0;
/* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
@@ -653,7 +668,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
#endif
return iwl_is_channel_extension(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel),
- iwl_ht_conf->extension_chan_offset);
+ ht_conf->extension_chan_offset);
}
EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
@@ -877,11 +892,11 @@ u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
- if (!ht_info->is_ht) {
+ if (!ht_conf->is_ht) {
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
RXON_FLG_HT40_PROT_MSK |
@@ -892,7 +907,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
/* FIXME: if the definition of ht_protection changed, the "translation"
* will be needed for rxon->flags
*/
- rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
+ rxon->flags |= cpu_to_le32(ht_conf->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
/* Set up channel bandwidth:
* 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
@@ -901,10 +916,10 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
if (iwl_is_ht40_tx_allowed(priv, NULL)) {
/* pure ht40 */
- if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
+ if (ht_conf->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
/* Note: control channel is opposite of extension channel */
- switch (ht_info->extension_chan_offset) {
+ switch (ht_conf->extension_chan_offset) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
break;
@@ -914,7 +929,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
}
} else {
/* Note: control channel is opposite of extension channel */
- switch (ht_info->extension_chan_offset) {
+ switch (ht_conf->extension_chan_offset) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
@@ -937,14 +952,10 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
- IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X "
- "rxon flags 0x%X operation mode :0x%X "
+ IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
"extension channel offset 0x%x\n",
- ht_info->mcs.rx_mask[0],
- ht_info->mcs.rx_mask[1],
- ht_info->mcs.rx_mask[2],
- le32_to_cpu(rxon->flags), ht_info->ht_protection,
- ht_info->extension_chan_offset);
+ le32_to_cpu(rxon->flags), ht_conf->ht_protection,
+ ht_conf->extension_chan_offset);
return;
}
EXPORT_SYMBOL(iwl_set_rxon_ht);
@@ -954,47 +965,37 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
#define IWL_NUM_IDLE_CHAINS_DUAL 2
#define IWL_NUM_IDLE_CHAINS_SINGLE 1
-/* Determine how many receiver/antenna chains to use.
- * More provides better reception via diversity. Fewer saves power.
+/*
+ * Determine how many receiver/antenna chains to use.
+ *
+ * More provides better reception via diversity. Fewer saves power
+ * at the expense of throughput, but only when not in powersave to
+ * start with.
+ *
* MIMO (dual stream) requires at least 2, but works better with 3.
* This does not determine *which* chains to use, just how many.
*/
static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
{
- bool is_single = is_single_rx_stream(priv);
- bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-
/* # of Rx chains to use when expecting MIMO. */
- if (is_single || (!is_cam && (priv->current_ht_config.sm_ps ==
- WLAN_HT_CAP_SM_PS_STATIC)))
+ if (is_single_rx_stream(priv))
return IWL_NUM_RX_CHAINS_SINGLE;
else
return IWL_NUM_RX_CHAINS_MULTIPLE;
}
+/*
+ * When we are in power saving, there's no difference between
+ * using multiple chains or just a single chain, but due to the
+ * lack of SM PS we lose a lot of throughput if we use just a
+ * single chain.
+ *
+ * Therefore, use the active count here (which will use multiple
+ * chains unless connected to a legacy AP).
+ */
static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
{
- int idle_cnt;
- bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
- /* # Rx chains when idling and maybe trying to save power */
- switch (priv->current_ht_config.sm_ps) {
- case WLAN_HT_CAP_SM_PS_STATIC:
- case WLAN_HT_CAP_SM_PS_DYNAMIC:
- idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
- IWL_NUM_IDLE_CHAINS_SINGLE;
- break;
- case WLAN_HT_CAP_SM_PS_DISABLED:
- idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
- break;
- case WLAN_HT_CAP_SM_PS_INVALID:
- default:
- IWL_ERR(priv, "invalid mimo ps mode %d\n",
- priv->current_ht_config.sm_ps);
- WARN_ON(1);
- idle_cnt = -1;
- break;
- }
- return idle_cnt;
+ return active_cnt;
}
/* up to 4 chains */
@@ -1004,7 +1005,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
res = (chain_bitmap & BIT(0)) >> 0;
res += (chain_bitmap & BIT(1)) >> 1;
res += (chain_bitmap & BIT(2)) >> 2;
- res += (chain_bitmap & BIT(4)) >> 4;
+ res += (chain_bitmap & BIT(3)) >> 3;
return res;
}
@@ -1280,13 +1281,18 @@ static void iwl_set_rate(struct iwl_priv *priv)
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
- IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n",
- le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
- rxon->channel = csa->channel;
- priv->staging_rxon.channel = csa->channel;
+
+ if (!le32_to_cpu(csa->status)) {
+ rxon->channel = csa->channel;
+ priv->staging_rxon.channel = csa->channel;
+ IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
+ le16_to_cpu(csa->channel));
+ } else
+ IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+ le16_to_cpu(csa->channel));
}
EXPORT_SYMBOL(iwl_rx_csa);
@@ -1345,6 +1351,156 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_irq_handle_error);
+int iwl_apm_stop_master(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set stop master bit */
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+ iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO(priv, "stop master\n");
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_apm_stop_master);
+
+void iwl_apm_stop(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
+
+ iwl_apm_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+ /* clear "init complete" move adapter D0A* --> D0U state */
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(iwl_apm_stop);
+
+
+/*
+ * Start up NIC's basic functionality after it has been reset
+ * (e.g. after platform boot, or shutdown via iwl_apm_stop())
+ * NOTE: This does not load uCode nor start the embedded processor
+ */
+int iwl_apm_init(struct iwl_priv *priv)
+{
+ int ret = 0;
+ u16 lctl;
+
+ IWL_DEBUG_INFO(priv, "Init card's basic functions\n");
+
+ /*
+ * Use "set_bit" below rather than "write", to preserve any hardware
+ * bits already set by default after reset.
+ */
+
+ /* Disable L0S exit timer (platform NMI Work/Around) */
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+ /*
+ * Disable L0s without affecting L1;
+ * don't wait for ICH L0s (ICH bug W/A)
+ */
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+ /* Set FH wait threshold to maximum (HW error during stress W/A) */
+ iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
+
+ /*
+ * Enable HAP INTA (interrupt from management bus) to
+ * wake device's PCI Express link L1a -> L0s
+ * NOTE: This is no-op for 3945 (non-existant bit)
+ */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
+
+ /*
+ * HW bug W/A - costs negligible power consumption ...
+ * Check if BIOS (or OS) enabled L1-ASPM on this device
+ */
+ if (priv->cfg->set_l0s) {
+ lctl = iwl_pcie_link_ctl(priv);
+ if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
+ PCI_CFG_LINK_CTRL_VAL_L1_EN) {
+ /* L1-ASPM enabled; disable(!) L0S */
+ iwl_set_bit(priv, CSR_GIO_REG,
+ CSR_GIO_REG_VAL_L0S_ENABLED);
+ IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
+ } else {
+ /* L1-ASPM disabled; enable(!) L0S */
+ iwl_clear_bit(priv, CSR_GIO_REG,
+ CSR_GIO_REG_VAL_L0S_ENABLED);
+ IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
+ }
+ }
+
+ /* Configure analog phase-lock-loop before activating to D0A */
+ if (priv->cfg->pll_cfg_val)
+ iwl_set_bit(priv, CSR_ANA_PLL_CFG, priv->cfg->pll_cfg_val);
+
+ /*
+ * Set "initialization complete" bit to move adapter from
+ * D0U* --> D0A* (powered-up active) state.
+ */
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ /*
+ * Wait for clock stabilization; once stabilized, access to
+ * device-internal resources is supported, e.g. iwl_write_prph()
+ * and accesses to uCode SRAM.
+ */
+ ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (ret < 0) {
+ IWL_DEBUG_INFO(priv, "Failed to init the card\n");
+ goto out;
+ }
+
+ /*
+ * Enable DMA and BSM (if used) clocks, wait for them to stabilize.
+ * BSM (Boostrap State Machine) is only in 3945 and 4965;
+ * later devices (i.e. 5000 and later) have non-volatile SRAM,
+ * and don't need BSM to restore data after power-saving sleep.
+ *
+ * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
+ * do not disable clocks. This preserves any hardware bits already
+ * set by default in "CLK_CTRL_REG" after reset.
+ */
+ if (priv->cfg->use_bsm)
+ iwl_write_prph(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
+ else
+ iwl_write_prph(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ udelay(20);
+
+ /* Disable L1-Active */
+ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(iwl_apm_init);
+
+
+
void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -1392,73 +1548,14 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(iwl_configure_filter);
-int iwl_setup_mac(struct iwl_priv *priv)
-{
- int ret;
- struct ieee80211_hw *hw = priv->hw;
- hw->rate_control_algorithm = "iwl-agn-rs";
-
- /* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT;
-
- if (!priv->cfg->broken_powersave)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
-
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
-
- hw->wiphy->custom_regulatory = true;
-
- /* Firmware does not support this */
- hw->wiphy->disable_beacon_hints = true;
-
- /*
- * For now, disable PS by default because it affects
- * RX performance significantly.
- */
- hw->wiphy->ps_default = false;
-
- hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
- /* we create the 802.11 header and a zero-length SSID element */
- hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
-
- /* Default value; 4 EDCA QOS priorities */
- hw->queues = 4;
-
- hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
-
- if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &priv->bands[IEEE80211_BAND_2GHZ];
- if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &priv->bands[IEEE80211_BAND_5GHZ];
-
- ret = ieee80211_register_hw(priv->hw);
- if (ret) {
- IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
- return ret;
- }
- priv->mac80211_registered = 1;
-
- return 0;
-}
-EXPORT_SYMBOL(iwl_setup_mac);
-
int iwl_set_hw_params(struct iwl_priv *priv)
{
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K)
- priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K;
+ priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
else
- priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
- priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+ priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
@@ -1487,15 +1584,12 @@ int iwl_init_drv(struct iwl_priv *priv)
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
- priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ;
priv->iw_mode = NL80211_IFTYPE_STATION;
- priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
-
/* Choose which receivers/antennas to use */
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -1914,9 +2008,9 @@ EXPORT_SYMBOL(iwl_isr_legacy);
int iwl_send_bt_config(struct iwl_priv *priv)
{
struct iwl_bt_cmd bt_cmd = {
- .flags = 3,
- .lead_time = 0xAA,
- .max_kill = 1,
+ .flags = BT_COEX_MODE_4W,
+ .lead_time = BT_LEAD_TIME_DEF,
+ .max_kill = BT_MAX_KILL_DEF,
.kill_ack_mask = 0,
.kill_cts_mask = 0,
};
@@ -2076,10 +2170,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
priv->thermal_throttle.ct_kill_toggle = false;
- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
- case CSR_HW_REV_TYPE_1000:
- case CSR_HW_REV_TYPE_6x00:
- case CSR_HW_REV_TYPE_6x50:
+ if (priv->cfg->support_ct_kill_exit) {
adv_cmd.critical_temperature_enter =
cpu_to_le32(priv->hw_params.ct_kill_threshold);
adv_cmd.critical_temperature_exit =
@@ -2096,8 +2187,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
"exit is %d\n",
priv->hw_params.ct_kill_threshold,
priv->hw_params.ct_kill_exit_threshold);
- break;
- default:
+ } else {
cmd.critical_temperature_R =
cpu_to_le32(priv->hw_params.ct_kill_threshold);
@@ -2110,7 +2200,6 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
"succeeded, "
"critical temperature is %d\n",
priv->hw_params.ct_kill_threshold);
- break;
}
}
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
@@ -2142,7 +2231,7 @@ void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
sleep->pm_sleep_mode, sleep->pm_wakeup_src);
@@ -2153,7 +2242,7 @@ EXPORT_SYMBOL(iwl_rx_pm_sleep_notif);
void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
"notification for %s:\n", len,
@@ -2165,7 +2254,7 @@ EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
void iwl_rx_reply_error(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
"seq 0x%04X ser 0x%08X\n",
@@ -2227,42 +2316,58 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
EXPORT_SYMBOL(iwl_mac_conf_tx);
static void iwl_ht_conf(struct iwl_priv *priv,
- struct ieee80211_bss_conf *bss_conf)
+ struct ieee80211_bss_conf *bss_conf)
{
- struct ieee80211_sta_ht_cap *ht_conf;
- struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
struct ieee80211_sta *sta;
IWL_DEBUG_MAC80211(priv, "enter: \n");
- if (!iwl_conf->is_ht)
+ if (!ht_conf->is_ht)
return;
+ ht_conf->ht_protection =
+ bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+ ht_conf->non_GF_STA_present =
+ !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
- /*
- * It is totally wrong to base global information on something
- * that is valid only when associated, alas, this driver works
- * that way and I don't know how to fix it.
- */
+ ht_conf->single_chain_sufficient = false;
- rcu_read_lock();
- sta = ieee80211_find_sta(priv->hw, priv->bssid);
- if (!sta) {
+ switch (priv->iw_mode) {
+ case NL80211_IFTYPE_STATION:
+ rcu_read_lock();
+ sta = ieee80211_find_sta(priv->hw, priv->bssid);
+ if (sta) {
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ int maxstreams;
+
+ maxstreams = (ht_cap->mcs.tx_params &
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
+ >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+ maxstreams += 1;
+
+ if ((ht_cap->mcs.rx_mask[1] == 0) &&
+ (ht_cap->mcs.rx_mask[2] == 0))
+ ht_conf->single_chain_sufficient = true;
+ if (maxstreams <= 1)
+ ht_conf->single_chain_sufficient = true;
+ } else {
+ /*
+ * If at all, this can only happen through a race
+ * when the AP disconnects us while we're still
+ * setting up the connection, in that case mac80211
+ * will soon tell us about that.
+ */
+ ht_conf->single_chain_sufficient = true;
+ }
rcu_read_unlock();
- return;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ht_conf->single_chain_sufficient = true;
+ break;
+ default:
+ break;
}
- ht_conf = &sta->ht_cap;
-
- iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
-
- memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
-
- iwl_conf->ht_protection =
- bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
- iwl_conf->non_GF_STA_present =
- !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-
- rcu_read_unlock();
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -2386,6 +2491,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
priv->timestamp = bss_conf->timestamp;
priv->assoc_capability = bss_conf->assoc_capability;
+ iwl_led_associate(priv);
+
/*
* We have just associated, don't start scan too early
* leave time for EAPOL exchange to complete.
@@ -2396,9 +2503,10 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
if (!iwl_is_rfkill(priv))
priv->cfg->ops->lib->post_associate(priv);
- } else
+ } else {
priv->assoc_id = 0;
-
+ iwl_led_disassociate(priv);
+ }
}
if (changes && iwl_is_associated(priv) && priv->assoc_id) {
@@ -2569,7 +2677,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
struct iwl_priv *priv = hw->priv;
const struct iwl_channel_info *ch_info;
struct ieee80211_conf *conf = &hw->conf;
- struct iwl_ht_info *ht_conf = &priv->current_ht_config;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
unsigned long flags = 0;
int ret = 0;
u16 ch;
@@ -2611,6 +2719,14 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
goto set_ch_out;
}
+ if (iwl_is_associated(priv) &&
+ (le16_to_cpu(priv->active_rxon.channel) != ch) &&
+ priv->cfg->ops->lib->set_channel_switch) {
+ ret = priv->cfg->ops->lib->set_channel_switch(priv,
+ ch);
+ goto out;
+ }
+
spin_lock_irqsave(&priv->lock, flags);
/* Configure HT40 channels */
@@ -2619,21 +2735,18 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
if (conf_is_ht40_minus(conf)) {
ht_conf->extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- ht_conf->supported_chan_width =
- IWL_CHANNEL_WIDTH_40MHZ;
+ ht_conf->is_40mhz = true;
} else if (conf_is_ht40_plus(conf)) {
ht_conf->extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- ht_conf->supported_chan_width =
- IWL_CHANNEL_WIDTH_40MHZ;
+ ht_conf->is_40mhz = true;
} else {
ht_conf->extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_NONE;
- ht_conf->supported_chan_width =
- IWL_CHANNEL_WIDTH_20MHZ;
+ ht_conf->is_40mhz = false;
}
} else
- ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+ ht_conf->is_40mhz = false;
/* Default to no protection. Protection mode will later be set
* from BSS config in iwl_ht_conf */
ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
@@ -2655,7 +2768,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_rate(priv);
}
- if (changed & IEEE80211_CONF_CHANGE_PS) {
+ if (changed & (IEEE80211_CONF_CHANGE_PS |
+ IEEE80211_CONF_CHANGE_IDLE)) {
ret = iwl_power_update_mode(priv, false);
if (ret)
IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
@@ -2739,7 +2853,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211(priv, "enter\n");
spin_lock_irqsave(&priv->lock, flags);
- memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
+ memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
spin_unlock_irqrestore(&priv->lock, flags);
iwl_reset_qos(priv);
@@ -2791,6 +2905,27 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(iwl_mac_reset_tsf);
+int iwl_alloc_txq_mem(struct iwl_priv *priv)
+{
+ if (!priv->txq)
+ priv->txq = kzalloc(
+ sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues,
+ GFP_KERNEL);
+ if (!priv->txq) {
+ IWL_ERR(priv, "Not enough memory for txq \n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iwl_alloc_txq_mem);
+
+void iwl_free_txq_mem(struct iwl_priv *priv)
+{
+ kfree(priv->txq);
+ priv->txq = NULL;
+}
+EXPORT_SYMBOL(iwl_free_txq_mem);
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index e50103a956b..b875dcfca2d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -89,6 +89,7 @@ struct iwl_hcmd_ops {
int (*rxon_assoc)(struct iwl_priv *priv);
int (*commit_rxon)(struct iwl_priv *priv);
void (*set_rxon_chain)(struct iwl_priv *priv);
+ int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
};
struct iwl_hcmd_utils_ops {
@@ -97,7 +98,8 @@ struct iwl_hcmd_utils_ops {
void (*gain_computation)(struct iwl_priv *priv,
u32 *average_noise,
u16 min_average_noise_antennat_i,
- u32 min_average_noise);
+ u32 min_average_noise,
+ u8 default_chain);
void (*chain_noise_reset)(struct iwl_priv *priv);
void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
__le32 *tx_flags);
@@ -107,7 +109,6 @@ struct iwl_hcmd_utils_ops {
struct iwl_apm_ops {
int (*init)(struct iwl_priv *priv);
- int (*reset)(struct iwl_priv *priv);
void (*stop)(struct iwl_priv *priv);
void (*config)(struct iwl_priv *priv);
int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
@@ -168,6 +169,7 @@ struct iwl_lib_ops {
int (*load_ucode)(struct iwl_priv *priv);
void (*dump_nic_event_log)(struct iwl_priv *priv);
void (*dump_nic_error_log)(struct iwl_priv *priv);
+ int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
/* power management */
struct iwl_apm_ops apm_ops;
@@ -185,18 +187,24 @@ struct iwl_lib_ops {
struct iwl_temp_ops temp_ops;
};
+struct iwl_led_ops {
+ int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd);
+ int (*on)(struct iwl_priv *priv);
+ int (*off)(struct iwl_priv *priv);
+};
+
struct iwl_ops {
const struct iwl_ucode_ops *ucode;
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
+ const struct iwl_led_ops *led;
};
struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
- int num_of_ampdu_queues;/* def: HW dependent */
int disable_11n; /* def: 0 = 11n capabilities enabled */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
int antenna; /* def: 0 = both antennas (use diversity) */
@@ -213,6 +221,13 @@ struct iwl_mod_params {
* @pa_type: used by 6000 series only to identify the type of Power Amplifier
* @max_ll_items: max number of OTP blocks
* @shadow_ram_support: shadow support for OTP memory
+ * @led_compensation: compensate on the led on/off time per HW according
+ * to the deviation to achieve the desired led frequency.
+ * The detail algorithm is described in iwl-led.c
+ * @use_rts_for_ht: use rts/cts protection for HT traffic
+ * @chain_noise_num_beacons: number of beacons used to compute chain noise
+ * @adv_thermal_throttle: support advance thermal throttle
+ * @support_ct_kill_exit: support ct kill exit condition
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -244,17 +259,30 @@ struct iwl_cfg {
int eeprom_size;
u16 eeprom_ver;
u16 eeprom_calib_ver;
+ int num_of_queues; /* def: HW dependent */
+ int num_of_ampdu_queues;/* def: HW dependent */
const struct iwl_ops *ops;
const struct iwl_mod_params *mod_params;
u8 valid_tx_ant;
u8 valid_rx_ant;
- bool need_pll_cfg;
+
+ /* for iwl_apm_init() */
+ u32 pll_cfg_val;
+ bool set_l0s;
+ bool use_bsm;
+
bool use_isr_legacy;
enum iwl_pa_type pa_type;
const u16 max_ll_items;
const bool shadow_ram_support;
const bool ht_greenfield_support;
+ u16 led_compensation;
const bool broken_powersave;
+ bool use_rts_for_ht;
+ int chain_noise_num_beacons;
+ const bool supports_idle;
+ bool adv_thermal_throttle;
+ bool support_ct_kill_exit;
};
/***************************
@@ -273,7 +301,7 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv);
int iwl_full_rxon_required(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf);
void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band);
@@ -287,7 +315,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags, u64 multicast);
int iwl_hw_nic_init(struct iwl_priv *priv);
-int iwl_setup_mac(struct iwl_priv *priv);
int iwl_set_hw_params(struct iwl_priv *priv);
int iwl_init_drv(struct iwl_priv *priv);
void iwl_uninit_drv(struct iwl_priv *priv);
@@ -309,6 +336,10 @@ void iwl_config_ap(struct iwl_priv *priv);
int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats);
void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
+int iwl_alloc_txq_mem(struct iwl_priv *priv);
+void iwl_free_txq_mem(struct iwl_priv *priv);
+void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+ __le32 *tx_flags);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv);
@@ -509,7 +540,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
const void *data,
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb));
+ struct iwl_rx_packet *pkt));
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
@@ -569,6 +600,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
#define STATUS_INT_ENABLED 2
#define STATUS_RF_KILL_HW 3
+#define STATUS_CT_KILL 4
#define STATUS_INIT 5
#define STATUS_ALIVE 6
#define STATUS_READY 7
@@ -613,6 +645,11 @@ static inline int iwl_is_rfkill(struct iwl_priv *priv)
return iwl_is_rfkill_hw(priv);
}
+static inline int iwl_is_ctkill(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_CT_KILL, &priv->status);
+}
+
static inline int iwl_is_ready_rf(struct iwl_priv *priv)
{
@@ -634,6 +671,9 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_apm_stop(struct iwl_priv *priv);
+int iwl_apm_stop_master(struct iwl_priv *priv);
+int iwl_apm_init(struct iwl_priv *priv);
void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
@@ -653,5 +693,4 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
{
return priv->hw->wiphy->bands[band];
}
-
#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 06437d13e73..b6ed5a3147a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -109,8 +109,9 @@
* Bit fields:
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
*/
-#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
-#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
+#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
+#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
+#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
/* Bits for CSR_HW_IF_CONFIG_REG */
#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010)
@@ -195,6 +196,7 @@
#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
+#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000)
/* GP (general purpose) CONTROL */
#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
@@ -230,12 +232,22 @@
/* EEPROM GP */
#define CSR_EEPROM_GP_VALID_MSK (0x00000007)
-#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
#define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */
#define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */
#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */
#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */
+#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */
+#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
+#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
+#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
+#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000)
+
+/* EEPROM signature */
+#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000)
+#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004)
/* CSR GIO */
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index cbc62904655..96c92eab692 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -84,9 +84,7 @@ struct iwl_debugfs {
struct dentry *file_interrupt;
struct dentry *file_qos;
struct dentry *file_thermal_throttling;
-#ifdef CONFIG_IWLWIFI_LEDS
struct dentry *file_led;
-#endif
struct dentry *file_disable_ht40;
struct dentry *file_sleep_level_override;
struct dentry *file_current_sleep_command;
@@ -108,6 +106,7 @@ struct iwl_debugfs {
struct dentry *file_sensitivity;
struct dentry *file_chain_noise;
struct dentry *file_tx_power;
+ struct dentry *file_power_save_status;
} dbgfs_debug_files;
u32 sram_offset;
u32 sram_len;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index a198bcf6102..8784911fd56 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -383,6 +383,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
int pos = 0, ofs = 0, buf_size = 0;
const u8 *ptr;
char *buf;
+ u16 eeprom_ver;
size_t eeprom_len = priv->cfg->eeprom_size;
buf_size = 4 * eeprom_len + 256;
@@ -403,9 +404,11 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
IWL_ERR(priv, "Can not allocate Buffer\n");
return -ENOMEM;
}
- pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n",
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+ pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
+ "version: 0x%x\n",
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- ? "OTP" : "EEPROM");
+ ? "OTP" : "EEPROM", eeprom_ver);
for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
@@ -532,6 +535,8 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
test_bit(STATUS_INT_ENABLED, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
test_bit(STATUS_RF_KILL_HW, &priv->status));
+ pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
+ test_bit(STATUS_CT_KILL, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
test_bit(STATUS_INIT, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
@@ -672,7 +677,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
return ret;
}
-#ifdef CONFIG_IWLWIFI_LEDS
static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -697,7 +701,6 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
}
-#endif
static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
char __user *user_buf,
@@ -798,15 +801,20 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
* valid here. However, let's not confuse them and present
* IWL_POWER_INDEX_1 as "1", not "0".
*/
- if (value > 0)
+ if (value == 0)
+ return -EINVAL;
+ else if (value > 0)
value -= 1;
if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
return -EINVAL;
+ if (!iwl_is_ready_rf(priv))
+ return -EAGAIN;
+
priv->power_data.debug_sleep_level_override = value;
- iwl_power_update_mode(priv, false);
+ iwl_power_update_mode(priv, true);
return count;
}
@@ -861,9 +869,7 @@ DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status);
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
DEBUGFS_READ_FILE_OPS(qos);
-#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_READ_FILE_OPS(led);
-#endif
DEBUGFS_READ_FILE_OPS(thermal_throttling);
DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
@@ -881,10 +887,14 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
struct iwl_rx_queue *rxq = &priv->rxq;
char *buf;
int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
- (IWL_MAX_NUM_QUEUES * 32 * 8) + 400;
+ (priv->cfg->num_of_queues * 32 * 8) + 400;
const u8 *ptr;
ssize_t ret;
+ if (!priv->txq) {
+ IWL_ERR(priv, "txq not ready\n");
+ return -EAGAIN;
+ }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
IWL_ERR(priv, "Can not allocate buffer\n");
@@ -976,8 +986,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
int pos = 0;
int cnt;
int ret;
- const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES;
+ const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues;
+ if (!priv->txq) {
+ IWL_ERR(priv, "txq not ready\n");
+ return -EAGAIN;
+ }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -1068,10 +1082,10 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
sizeof(struct statistics_rx_non_phy) * 20 +
sizeof(struct statistics_rx_ht_phy) * 20 + 400;
ssize_t ret;
- struct statistics_rx_phy *ofdm;
- struct statistics_rx_phy *cck;
- struct statistics_rx_non_phy *general;
- struct statistics_rx_ht_phy *ht;
+ struct statistics_rx_phy *ofdm, *accum_ofdm;
+ struct statistics_rx_phy *cck, *accum_cck;
+ struct statistics_rx_non_phy *general, *accum_general;
+ struct statistics_rx_ht_phy *ht, *accum_ht;
if (!iwl_is_alive(priv))
return -EAGAIN;
@@ -1100,155 +1114,268 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
cck = &priv->statistics.rx.cck;
general = &priv->statistics.rx.general;
ht = &priv->statistics.rx.ofdm_ht;
+ accum_ofdm = &priv->accum_statistics.rx.ofdm;
+ accum_cck = &priv->accum_statistics.rx.cck;
+ accum_general = &priv->accum_statistics.rx.general;
+ accum_ht = &priv->accum_statistics.rx.ofdm_ht;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
- le32_to_cpu(ofdm->ina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
- le32_to_cpu(ofdm->fina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
- le32_to_cpu(ofdm->plcp_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
- le32_to_cpu(ofdm->crc32_err));
- pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
- le32_to_cpu(ofdm->overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
- le32_to_cpu(ofdm->early_overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
- le32_to_cpu(ofdm->crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
- le32_to_cpu(ofdm->false_alarm_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
- le32_to_cpu(ofdm->fina_sync_err_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
- le32_to_cpu(ofdm->sfd_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
- le32_to_cpu(ofdm->fina_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
- le32_to_cpu(ofdm->unresponded_rts));
- pos += scnprintf(buf + pos, bufsz - pos,
- "rxe_frame_limit_overrun: %u\n",
- le32_to_cpu(ofdm->rxe_frame_limit_overrun));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n",
- le32_to_cpu(ofdm->sent_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n",
- le32_to_cpu(ofdm->sent_cts_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n",
- le32_to_cpu(ofdm->sent_ba_rsp_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n",
- le32_to_cpu(ofdm->dsp_self_kill));
- pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
- le32_to_cpu(ofdm->mh_format_err));
- pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n",
- le32_to_cpu(ofdm->re_acq_main_rssi_sum));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "overrun_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->overrun_err),
+ accum_ofdm->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "early_overrun_err:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->early_overrun_err),
+ accum_ofdm->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->crc32_good),
+ accum_ofdm->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "false_alarm_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->false_alarm_cnt),
+ accum_ofdm->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->fina_sync_err_cnt),
+ accum_ofdm->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sfd_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sfd_timeout),
+ accum_ofdm->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->fina_timeout),
+ accum_ofdm->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "unresponded_rts:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->unresponded_rts),
+ accum_ofdm->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+ accum_ofdm->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sent_ack_cnt),
+ accum_ofdm->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sent_cts_cnt),
+ accum_ofdm->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sent_ba_rsp_cnt),
+ accum_ofdm->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dsp_self_kill:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->dsp_self_kill),
+ accum_ofdm->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "mh_format_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->mh_format_err),
+ accum_ofdm->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->re_acq_main_rssi_sum),
+ accum_ofdm->re_acq_main_rssi_sum);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
- le32_to_cpu(cck->ina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
- le32_to_cpu(cck->fina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
- le32_to_cpu(cck->plcp_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
- le32_to_cpu(cck->crc32_err));
- pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
- le32_to_cpu(cck->overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
- le32_to_cpu(cck->early_overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
- le32_to_cpu(cck->crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
- le32_to_cpu(cck->false_alarm_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
- le32_to_cpu(cck->fina_sync_err_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
- le32_to_cpu(cck->sfd_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
- le32_to_cpu(cck->fina_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
- le32_to_cpu(cck->unresponded_rts));
- pos += scnprintf(buf + pos, bufsz - pos,
- "rxe_frame_limit_overrun: %u\n",
- le32_to_cpu(cck->rxe_frame_limit_overrun));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n",
- le32_to_cpu(cck->sent_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n",
- le32_to_cpu(cck->sent_cts_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n",
- le32_to_cpu(cck->sent_ba_rsp_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n",
- le32_to_cpu(cck->dsp_self_kill));
- pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
- le32_to_cpu(cck->mh_format_err));
- pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n",
- le32_to_cpu(cck->re_acq_main_rssi_sum));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->plcp_err), accum_cck->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->crc32_err), accum_cck->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "overrun_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->overrun_err),
+ accum_cck->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "early_overrun_err:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->early_overrun_err),
+ accum_cck->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->crc32_good), accum_cck->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "false_alarm_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->false_alarm_cnt),
+ accum_cck->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->fina_sync_err_cnt),
+ accum_cck->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sfd_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sfd_timeout),
+ accum_cck->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->fina_timeout),
+ accum_cck->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "unresponded_rts:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->unresponded_rts),
+ accum_cck->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->rxe_frame_limit_overrun),
+ accum_cck->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sent_ack_cnt),
+ accum_cck->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sent_cts_cnt),
+ accum_cck->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sent_ba_rsp_cnt),
+ accum_cck->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dsp_self_kill:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->dsp_self_kill),
+ accum_cck->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "mh_format_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->mh_format_err),
+ accum_cck->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->re_acq_main_rssi_sum),
+ accum_cck->re_acq_main_rssi_sum);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n",
- le32_to_cpu(general->bogus_cts));
- pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n",
- le32_to_cpu(general->bogus_ack));
- pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n",
- le32_to_cpu(general->non_bssid_frames));
- pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n",
- le32_to_cpu(general->filtered_frames));
- pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n",
- le32_to_cpu(general->non_channel_beacons));
- pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n",
- le32_to_cpu(general->channel_beacons));
- pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n",
- le32_to_cpu(general->num_missed_bcon));
- pos += scnprintf(buf + pos, bufsz - pos,
- "adc_rx_saturation_time: %u\n",
- le32_to_cpu(general->adc_rx_saturation_time));
- pos += scnprintf(buf + pos, bufsz - pos,
- "ina_detection_search_time: %u\n",
- le32_to_cpu(general->ina_detection_search_time));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n",
- le32_to_cpu(general->beacon_silence_rssi_a));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n",
- le32_to_cpu(general->beacon_silence_rssi_b));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n",
- le32_to_cpu(general->beacon_silence_rssi_c));
- pos += scnprintf(buf + pos, bufsz - pos,
- "interference_data_flag: %u\n",
- le32_to_cpu(general->interference_data_flag));
- pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n",
- le32_to_cpu(general->channel_load));
- pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n",
- le32_to_cpu(general->dsp_false_alarms));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n",
- le32_to_cpu(general->beacon_rssi_a));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n",
- le32_to_cpu(general->beacon_rssi_b));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n",
- le32_to_cpu(general->beacon_rssi_c));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n",
- le32_to_cpu(general->beacon_energy_a));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n",
- le32_to_cpu(general->beacon_energy_b));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n",
- le32_to_cpu(general->beacon_energy_c));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->bogus_cts),
+ accum_general->bogus_cts);
+ pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->bogus_ack),
+ accum_general->bogus_ack);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "non_bssid_frames:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->non_bssid_frames),
+ accum_general->non_bssid_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "filtered_frames:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->filtered_frames),
+ accum_general->filtered_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "non_channel_beacons:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->non_channel_beacons),
+ accum_general->non_channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "channel_beacons:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->channel_beacons),
+ accum_general->channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "num_missed_bcon:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->num_missed_bcon),
+ accum_general->num_missed_bcon);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "adc_rx_saturation_time:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->adc_rx_saturation_time),
+ accum_general->adc_rx_saturation_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ina_detect_search_tm:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->ina_detection_search_time),
+ accum_general->ina_detection_search_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_silence_rssi_a:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_silence_rssi_a),
+ accum_general->beacon_silence_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_silence_rssi_b:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_silence_rssi_b),
+ accum_general->beacon_silence_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_silence_rssi_c:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_silence_rssi_c),
+ accum_general->beacon_silence_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "interference_data_flag:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->interference_data_flag),
+ accum_general->interference_data_flag);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "channel_load:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->channel_load),
+ accum_general->channel_load);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dsp_false_alarms:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->dsp_false_alarms),
+ accum_general->dsp_false_alarms);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_rssi_a:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_rssi_a),
+ accum_general->beacon_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_rssi_b:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_rssi_b),
+ accum_general->beacon_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_rssi_c:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_rssi_c),
+ accum_general->beacon_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_energy_a:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_energy_a),
+ accum_general->beacon_energy_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_energy_b:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_energy_b),
+ accum_general->beacon_energy_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_energy_c:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_energy_c),
+ accum_general->beacon_energy_c);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
- le32_to_cpu(ht->plcp_err));
- pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
- le32_to_cpu(ht->overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
- le32_to_cpu(ht->early_overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
- le32_to_cpu(ht->crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
- le32_to_cpu(ht->crc32_err));
- pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
- le32_to_cpu(ht->mh_format_err));
- pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n",
- le32_to_cpu(ht->agg_crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n",
- le32_to_cpu(ht->agg_mpdu_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n",
- le32_to_cpu(ht->agg_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->plcp_err), accum_ht->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "overrun_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->overrun_err), accum_ht->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "early_overrun_err:\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->early_overrun_err),
+ accum_ht->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->crc32_good), accum_ht->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->crc32_err), accum_ht->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "mh_format_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->mh_format_err),
+ accum_ht->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg_crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->agg_crc32_good),
+ accum_ht->agg_crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg_mpdu_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->agg_mpdu_cnt),
+ accum_ht->agg_mpdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -1264,7 +1391,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
char *buf;
int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
ssize_t ret;
- struct statistics_tx *tx;
+ struct statistics_tx *tx, *accum_tx;
if (!iwl_is_alive(priv))
return -EAGAIN;
@@ -1290,62 +1417,107 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
* might not reflect the current uCode activity
*/
tx = &priv->statistics.tx;
+ accum_tx = &priv->accum_statistics.tx;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n",
- le32_to_cpu(tx->preamble_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n",
- le32_to_cpu(tx->rx_detected_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n",
- le32_to_cpu(tx->bt_prio_defer_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n",
- le32_to_cpu(tx->bt_prio_kill_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n",
- le32_to_cpu(tx->few_bytes_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n",
- le32_to_cpu(tx->cts_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n",
- le32_to_cpu(tx->ack_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n",
- le32_to_cpu(tx->expected_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n",
- le32_to_cpu(tx->actual_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n",
- le32_to_cpu(tx->dump_msdu_cnt));
- pos += scnprintf(buf + pos, bufsz - pos,
- "burst_abort_next_frame_mismatch_cnt: %u\n",
- le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt));
- pos += scnprintf(buf + pos, bufsz - pos,
- "burst_abort_missing_next_frame_cnt: %u\n",
- le32_to_cpu(tx->burst_abort_missing_next_frame_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n",
- le32_to_cpu(tx->cts_timeout_collision));
- pos += scnprintf(buf + pos, bufsz - pos,
- "ack_or_ba_timeout_collision: %u\n",
- le32_to_cpu(tx->ack_or_ba_timeout_collision));
- pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n",
- le32_to_cpu(tx->agg.ba_timeout));
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg ba_reschedule_frames: %u\n",
- le32_to_cpu(tx->agg.ba_reschedule_frames));
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_agg_frame_cnt: %u\n",
- le32_to_cpu(tx->agg.scd_query_agg_frame_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n",
- le32_to_cpu(tx->agg.scd_query_no_agg));
- pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n",
- le32_to_cpu(tx->agg.scd_query_agg));
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_mismatch: %u\n",
- le32_to_cpu(tx->agg.scd_query_mismatch));
- pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n",
- le32_to_cpu(tx->agg.frame_not_ready));
- pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n",
- le32_to_cpu(tx->agg.underrun));
- pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n",
- le32_to_cpu(tx->agg.bt_prio_kill));
- pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n",
- le32_to_cpu(tx->agg.rx_ba_rsp_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->preamble_cnt),
+ accum_tx->preamble_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rx_detected_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->rx_detected_cnt),
+ accum_tx->rx_detected_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->bt_prio_defer_cnt),
+ accum_tx->bt_prio_defer_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->bt_prio_kill_cnt),
+ accum_tx->bt_prio_kill_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "few_bytes_cnt:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->few_bytes_cnt),
+ accum_tx->few_bytes_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "cts_timeout:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ack_timeout:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->ack_timeout),
+ accum_tx->ack_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "expected_ack_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->expected_ack_cnt),
+ accum_tx->expected_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "actual_ack_cnt:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->actual_ack_cnt),
+ accum_tx->actual_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->dump_msdu_cnt),
+ accum_tx->dump_msdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "abort_nxt_frame_mismatch:"
+ "\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
+ accum_tx->burst_abort_next_frame_mismatch_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "abort_missing_nxt_frame:"
+ "\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
+ accum_tx->burst_abort_missing_next_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "cts_timeout_collision:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->cts_timeout_collision),
+ accum_tx->cts_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ack_ba_timeout_collision:\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->ack_or_ba_timeout_collision),
+ accum_tx->ack_or_ba_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg ba_timeout:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.ba_timeout),
+ accum_tx->agg.ba_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg ba_resched_frames:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.ba_reschedule_frames),
+ accum_tx->agg.ba_reschedule_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_agg_frame:\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
+ accum_tx->agg.scd_query_agg_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_no_agg:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_no_agg),
+ accum_tx->agg.scd_query_no_agg);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_agg:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_agg),
+ accum_tx->agg.scd_query_agg);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_mismatch:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_mismatch),
+ accum_tx->agg.scd_query_mismatch);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg frame_not_ready:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.frame_not_ready),
+ accum_tx->agg.frame_not_ready);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg underrun:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.underrun),
+ accum_tx->agg.underrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg bt_prio_kill:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.bt_prio_kill),
+ accum_tx->agg.bt_prio_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
+ accum_tx->agg.rx_ba_rsp_cnt);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -1361,9 +1533,9 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
char *buf;
int bufsz = sizeof(struct statistics_general) * 4 + 250;
ssize_t ret;
- struct statistics_general *general;
- struct statistics_dbg *dbg;
- struct statistics_div *div;
+ struct statistics_general *general, *accum_general;
+ struct statistics_dbg *dbg, *accum_dbg;
+ struct statistics_div *div, *accum_div;
if (!iwl_is_alive(priv))
return -EAGAIN;
@@ -1391,34 +1563,53 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
general = &priv->statistics.general;
dbg = &priv->statistics.general.dbg;
div = &priv->statistics.general.div;
+ accum_general = &priv->accum_statistics.general;
+ accum_dbg = &priv->accum_statistics.general.dbg;
+ accum_div = &priv->accum_statistics.general.div;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n",
le32_to_cpu(general->temperature));
- pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n",
le32_to_cpu(general->temperature_m));
- pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n",
- le32_to_cpu(dbg->burst_check));
- pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n",
- le32_to_cpu(dbg->burst_count));
- pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n",
- le32_to_cpu(general->sleep_time));
- pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n",
- le32_to_cpu(general->slots_out));
- pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n",
- le32_to_cpu(general->slots_idle));
- pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "burst_check:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(dbg->burst_check),
+ accum_dbg->burst_check);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "burst_count:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(dbg->burst_count),
+ accum_dbg->burst_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sleep_time:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->sleep_time),
+ accum_general->sleep_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "slots_out:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->slots_out),
+ accum_general->slots_out);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "slots_idle:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->slots_idle),
+ accum_general->slots_idle);
+ pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
le32_to_cpu(general->ttl_timestamp));
- pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n",
- le32_to_cpu(div->tx_on_a));
- pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n",
- le32_to_cpu(div->tx_on_b));
- pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n",
- le32_to_cpu(div->exec_time));
- pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n",
- le32_to_cpu(div->probe_time));
- pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n",
- le32_to_cpu(general->rx_enable_counter));
+ pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->tx_on_a), accum_div->tx_on_a);
+ pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->tx_on_b), accum_div->tx_on_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "exec_time:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->exec_time), accum_div->exec_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "probe_time:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->probe_time), accum_div->probe_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rx_enable_counter:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->rx_enable_counter),
+ accum_general->rx_enable_counter);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
@@ -1614,6 +1805,29 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char buf[60];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+ u32 pwrsave_status;
+
+ pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_REG_POWER_SAVE_STATUS_MSK;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
+ pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+ (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
+ (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
+ (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
+ "error");
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1625,6 +1839,7 @@ DEBUGFS_READ_FILE_OPS(ucode_general_stats);
DEBUGFS_READ_FILE_OPS(sensitivity);
DEBUGFS_READ_FILE_OPS(chain_noise);
DEBUGFS_READ_FILE_OPS(tx_power);
+DEBUGFS_READ_FILE_OPS(power_save_status);
/*
* Create the debugfs files and directories
@@ -1661,9 +1876,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(status, data);
DEBUGFS_ADD_FILE(interrupt, data);
DEBUGFS_ADD_FILE(qos, data);
-#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_ADD_FILE(led, data);
-#endif
DEBUGFS_ADD_FILE(sleep_level_override, data);
DEBUGFS_ADD_FILE(current_sleep_command, data);
DEBUGFS_ADD_FILE(thermal_throttling, data);
@@ -1674,6 +1887,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(rx_queue, debug);
DEBUGFS_ADD_FILE(tx_queue, debug);
DEBUGFS_ADD_FILE(tx_power, debug);
+ DEBUGFS_ADD_FILE(power_save_status, debug);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
@@ -1716,9 +1930,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
-#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
-#endif
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40);
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
@@ -1728,6 +1940,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_ucode_rx_stats);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 028d5059955..e7ce6738766 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -43,7 +43,6 @@
#include "iwl-debug.h"
#include "iwl-4965-hw.h"
#include "iwl-3945-hw.h"
-#include "iwl-3945-led.h"
#include "iwl-led.h"
#include "iwl-power.h"
#include "iwl-agn-rs.h"
@@ -57,17 +56,22 @@ extern struct iwl_cfg iwl5100_bg_cfg;
extern struct iwl_cfg iwl5100_abg_cfg;
extern struct iwl_cfg iwl5150_agn_cfg;
extern struct iwl_cfg iwl6000h_2agn_cfg;
+extern struct iwl_cfg iwl6000h_2abg_cfg;
+extern struct iwl_cfg iwl6000h_2bg_cfg;
extern struct iwl_cfg iwl6000i_2agn_cfg;
+extern struct iwl_cfg iwl6000i_2abg_cfg;
+extern struct iwl_cfg iwl6000i_2bg_cfg;
extern struct iwl_cfg iwl6000_3agn_cfg;
extern struct iwl_cfg iwl6050_2agn_cfg;
+extern struct iwl_cfg iwl6050_2abg_cfg;
extern struct iwl_cfg iwl6050_3agn_cfg;
extern struct iwl_cfg iwl1000_bgn_cfg;
+extern struct iwl_cfg iwl1000_bg_cfg;
struct iwl_tx_queue;
/* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params;
-extern struct iwl_ops iwl5000_ops;
extern struct iwl_ucode_ops iwl5000_ucode;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd;
@@ -81,9 +85,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags);
extern int iwl5000_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp);
-extern int iwl5000_apm_init(struct iwl_priv *priv);
-extern void iwl5000_apm_stop(struct iwl_priv *priv);
-extern int iwl5000_apm_reset(struct iwl_priv *priv);
extern void iwl5000_nic_config(struct iwl_priv *priv);
extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
@@ -144,12 +145,13 @@ extern void iwl5000_temperature(struct iwl_priv *priv);
#define DEFAULT_LONG_RETRY_LIMIT 4U
struct iwl_rx_mem_buffer {
- dma_addr_t real_dma_addr;
- dma_addr_t aligned_dma_addr;
- struct sk_buff *skb;
+ dma_addr_t page_dma;
+ struct page *page;
struct list_head list;
};
+#define rxb_addr(r) page_address(r->page)
+
/* defined below */
struct iwl_device_cmd;
@@ -165,7 +167,7 @@ struct iwl_cmd_meta {
*/
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb);
+ struct iwl_rx_packet *pkt);
/* The CMD_SIZE_HUGE flag bit indicates that the command
* structure is stored at the end of the shared queue memory. */
@@ -321,6 +323,12 @@ struct iwl_channel_info {
* queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
#define IWL_MIN_NUM_QUEUES 10
+/*
+ * uCode queue management definitions ...
+ * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00.
+ */
+#define IWL_CMD_QUEUE_NUM 4
+
/* Power management (not Tx power) structures */
enum iwl_pwr_src {
@@ -356,7 +364,14 @@ enum {
CMD_WANT_SKB = (1 << 2),
};
-#define IWL_CMD_MAX_PAYLOAD 320
+#define DEF_CMD_PAYLOAD_SIZE 320
+
+/*
+ * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header,
+ * SNAP header and alignment. It should also be big enough for 802.11
+ * control frames.
+ */
+#define IWL_LINK_HDR_MAX 64
/**
* struct iwl_device_cmd
@@ -373,7 +388,8 @@ struct iwl_device_cmd {
u16 val16;
u32 val32;
struct iwl_tx_cmd tx;
- u8 payload[IWL_CMD_MAX_PAYLOAD];
+ struct iwl6000_channel_switch_cmd chswitch;
+ u8 payload[DEF_CMD_PAYLOAD_SIZE];
} __attribute__ ((packed)) cmd;
} __attribute__ ((packed));
@@ -382,21 +398,15 @@ struct iwl_device_cmd {
struct iwl_host_cmd {
const void *data;
- struct sk_buff *reply_skb;
+ unsigned long reply_page;
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb);
+ struct iwl_rx_packet *pkt);
u32 flags;
u16 len;
u8 id;
};
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
@@ -502,12 +512,11 @@ union iwl_ht_rate_supp {
#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
-struct iwl_ht_info {
+struct iwl_ht_config {
/* self configuration data */
- u8 is_ht;
- u8 supported_chan_width;
- u8 sm_ps;
- struct ieee80211_mcs_info mcs;
+ bool is_ht;
+ bool is_40mhz;
+ bool single_chain_sufficient;
/* BSS related data */
u8 extension_chan_offset;
u8 ht_protection;
@@ -561,6 +570,19 @@ struct iwl_station_entry {
struct iwl_hw_key keyinfo;
};
+/*
+ * iwl_station_priv: Driver's private station information
+ *
+ * When mac80211 creates a station it reserves some space (hw->sta_data_size)
+ * in the structure for use by driver. This structure is places in that
+ * space.
+ *
+ * At the moment use it for the station's rate scaling information.
+ */
+struct iwl_station_priv {
+ struct iwl_lq_sta lq_sta;
+};
+
/* one for each uCode image (inst/data, boot/init/runtime) */
struct fw_desc {
void *v_addr; /* access by driver */
@@ -622,6 +644,10 @@ struct iwl_sensitivity_ranges {
u16 auto_corr_max_cck_mrc;
u16 auto_corr_min_cck;
u16 auto_corr_min_cck_mrc;
+
+ u16 barker_corr_th_min;
+ u16 barker_corr_th_min_mrc;
+ u16 nrg_th_cca;
};
@@ -639,7 +665,7 @@ struct iwl_sensitivity_ranges {
* @valid_tx/rx_ant: usable antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
* @max_rxq_log: Log-base-2 of max_rxq_size
- * @rx_buf_size: Rx buffer size
+ * @rx_page_order: Rx buffer page order
* @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
* @max_stations:
* @bcast_sta_id:
@@ -662,9 +688,8 @@ struct iwl_hw_params {
u8 valid_rx_ant;
u16 max_rxq_size;
u16 max_rxq_log;
- u32 rx_buf_size;
+ u32 rx_page_order;
u32 rx_wrt_ptr_reg;
- u32 max_pkt_size;
u8 max_stations;
u8 bcast_sta_id;
u8 ht40_channel;
@@ -711,7 +736,11 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i)
static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
{
- /* This is for scan command, the big buffer at end of command array */
+ /*
+ * This is for init calibration result and scan command which
+ * required buffer > TFD_MAX_PAYLOAD_SIZE,
+ * the big buffer at end of command array
+ */
if (is_huge)
return q->n_window; /* must be power of 2 */
@@ -726,9 +755,6 @@ struct iwl_dma_ptr {
size_t size;
};
-#define IWL_CHANNEL_WIDTH_20MHZ 0
-#define IWL_CHANNEL_WIDTH_40MHZ 1
-
#define IWL_OPERATION_MODE_AUTO 0
#define IWL_OPERATION_MODE_HT_ONLY 1
#define IWL_OPERATION_MODE_MIXED 2
@@ -741,7 +767,8 @@ struct iwl_dma_ptr {
/* Sensitivity and chain noise calibration */
#define INITIALIZATION_VALUE 0xFFFF
-#define CAL_NUM_OF_BEACONS 20
+#define IWL4965_CAL_NUM_BEACONS 20
+#define IWL_CAL_NUM_BEACONS 16
#define MAXIMUM_ALLOWED_PATHLOSS 15
#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
@@ -845,6 +872,10 @@ struct iwl_sensitivity_data {
s32 nrg_auto_corr_silence_diff;
u32 num_in_cck_no_fa;
u32 nrg_th_ofdm;
+
+ u16 barker_corr_th_min;
+ u16 barker_corr_th_min_mrc;
+ u16 nrg_th_cca;
};
/* Chain noise (differential Rx gain) calib data */
@@ -961,8 +992,6 @@ struct traffic_stats {
};
#endif
-#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
-
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -976,7 +1005,7 @@ struct iwl_priv {
int frames_count;
enum ieee80211_band band;
- int alloc_rxb_skb;
+ int alloc_rxb_page;
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
@@ -1063,14 +1092,11 @@ struct iwl_priv {
struct iwl_init_alive_resp card_alive_init;
struct iwl_alive_resp card_alive;
-#ifdef CONFIG_IWLWIFI_LEDS
unsigned long last_blink_time;
u8 last_blink_rate;
u8 allow_blinking;
u64 led_tpt;
- struct iwl_led led[IWL_LED_TRG_MAX];
- unsigned int rxtxpackets;
-#endif
+
u16 active_rate;
u16 active_rate_basic;
@@ -1080,11 +1106,10 @@ struct iwl_priv {
struct iwl_chain_noise_data chain_noise_data;
__le16 sensitivity_tbl[HD_TABLE_SIZE];
- struct iwl_ht_info current_ht_config;
+ struct iwl_ht_config current_ht_config;
u8 last_phy_res[100];
/* Rate scaling data */
- s8 data_retry_limit;
u8 retry_rate;
wait_queue_head_t wait_command_queue;
@@ -1093,7 +1118,7 @@ struct iwl_priv {
/* Rx and Tx DMA processing queues */
struct iwl_rx_queue rxq;
- struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
+ struct iwl_tx_queue *txq;
unsigned long txq_ctx_active_msk;
struct iwl_dma_ptr kw; /* keep warm address */
struct iwl_dma_ptr scd_bc_tbls;
@@ -1116,7 +1141,9 @@ struct iwl_priv {
struct iwl_tt_mgmt thermal_throttle;
struct iwl_notif_statistics statistics;
- unsigned long last_statistics_time;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_notif_statistics accum_statistics;
+#endif
/* context information */
u16 rates_mask;
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
new file mode 100644
index 00000000000..4ef5acaa556
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -0,0 +1,13 @@
+#include <linux/module.h>
+
+/* sparse doesn't like tracepoint macros */
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "iwl-devtrace.h"
+
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
new file mode 100644
index 00000000000..8c7159208da
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -0,0 +1,178 @@
+#if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __IWLWIFI_DEVICE_TRACE
+
+#include <linux/tracepoint.h>
+#include "iwl-dev.h"
+
+#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+#define PRIV_ENTRY __field(struct iwl_priv *, priv)
+#define PRIV_ASSIGN __entry->priv = priv
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi
+
+TRACE_EVENT(iwlwifi_dev_ioread32,
+ TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+ TP_ARGS(priv, offs, val),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __field(u32, offs)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->offs = offs;
+ __entry->val = val;
+ ),
+ TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val)
+);
+
+TRACE_EVENT(iwlwifi_dev_iowrite32,
+ TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+ TP_ARGS(priv, offs, val),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __field(u32, offs)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->offs = offs;
+ __entry->val = val;
+ ),
+ TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
+);
+
+TRACE_EVENT(iwlwifi_dev_hcmd,
+ TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
+ TP_ARGS(priv, hcmd, len, flags),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __dynamic_array(u8, hcmd, len)
+ __field(u32, flags)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ memcpy(__get_dynamic_array(hcmd), hcmd, len);
+ __entry->flags = flags;
+ ),
+ TP_printk("[%p] hcmd %#.2x (%ssync)",
+ __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0],
+ __entry->flags & CMD_ASYNC ? "a" : "")
+);
+
+TRACE_EVENT(iwlwifi_dev_rx,
+ TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len),
+ TP_ARGS(priv, rxbuf, len),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __dynamic_array(u8, rxbuf, len)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ memcpy(__get_dynamic_array(rxbuf), rxbuf, len);
+ ),
+ TP_printk("[%p] RX cmd %#.2x",
+ __entry->priv, ((u8 *)__get_dynamic_array(rxbuf))[4])
+);
+
+TRACE_EVENT(iwlwifi_dev_tx,
+ TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen,
+ void *buf0, size_t buf0_len,
+ void *buf1, size_t buf1_len),
+ TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+
+ __field(size_t, framelen)
+ __dynamic_array(u8, tfd, tfdlen)
+
+ /*
+ * Do not insert between or below these items,
+ * we want to keep the frame together (except
+ * for the possible padding).
+ */
+ __dynamic_array(u8, buf0, buf0_len)
+ __dynamic_array(u8, buf1, buf1_len)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->framelen = buf0_len + buf1_len;
+ memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
+ memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
+ memcpy(__get_dynamic_array(buf1), buf1, buf0_len);
+ ),
+ TP_printk("[%p] TX %.2x (%zu bytes)",
+ __entry->priv,
+ ((u8 *)__get_dynamic_array(buf0))[0],
+ __entry->framelen)
+);
+
+TRACE_EVENT(iwlwifi_dev_ucode_error,
+ TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time,
+ u32 data1, u32 data2, u32 line, u32 blink1,
+ u32 blink2, u32 ilink1, u32 ilink2),
+ TP_ARGS(priv, desc, time, data1, data2, line,
+ blink1, blink2, ilink1, ilink2),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __field(u32, desc)
+ __field(u32, time)
+ __field(u32, data1)
+ __field(u32, data2)
+ __field(u32, line)
+ __field(u32, blink1)
+ __field(u32, blink2)
+ __field(u32, ilink1)
+ __field(u32, ilink2)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->desc = desc;
+ __entry->time = time;
+ __entry->data1 = data1;
+ __entry->data2 = data2;
+ __entry->line = line;
+ __entry->blink1 = blink1;
+ __entry->blink2 = blink2;
+ __entry->ilink1 = ilink1;
+ __entry->ilink2 = ilink2;
+ ),
+ TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, "
+ "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X",
+ __entry->priv, __entry->desc, __entry->time, __entry->data1,
+ __entry->data2, __entry->line, __entry->blink1,
+ __entry->blink2, __entry->ilink1, __entry->ilink2)
+);
+
+TRACE_EVENT(iwlwifi_dev_ucode_event,
+ TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+ TP_ARGS(priv, time, data, ev),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+
+ __field(u32, time)
+ __field(u32, data)
+ __field(u32, ev)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->time = time;
+ __entry->data = data;
+ __entry->ev = ev;
+ ),
+ TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
+ __entry->priv, __entry->time, __entry->data, __entry->ev)
+);
+#endif /* __IWLWIFI_DEVICE_TRACE */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE iwl-devtrace
+#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index e14c9952a93..9429cb1c69b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -215,12 +215,35 @@ static const struct iwl_txpwr_section enhinfo[] = {
int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
{
- u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
- if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
- IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
- return -ENOENT;
+ u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+ int ret = 0;
+
+ IWL_DEBUG_INFO(priv, "EEPROM signature=0x%08x\n", gp);
+ switch (gp) {
+ case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
+ if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
+ IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n",
+ gp);
+ ret = -ENOENT;
+ }
+ break;
+ case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
+ case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
+ if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
+ IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp);
+ ret = -ENOENT;
+ }
+ break;
+ case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
+ default:
+ IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, "
+ "EEPROM_GP=0x%08x\n",
+ (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+ ? "OTP" : "EEPROM", gp);
+ ret = -ENOENT;
+ break;
}
- return 0;
+ return ret;
}
EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
@@ -283,7 +306,8 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv)
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
/* See if we got it */
- ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG,
+ ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
EEPROM_SEM_TIMEOUT);
if (ret >= 0) {
@@ -322,7 +346,8 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock to be ready */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+ ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
25000);
if (ret < 0)
@@ -333,6 +358,14 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
+
+ /*
+ * CSR auto clock gate disable bit -
+ * this is only applicable for HW with OTP shadow RAM
+ */
+ if (priv->cfg->shadow_ram_support)
+ iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG,
+ CSR_RESET_LINK_PWR_MGMT_DISABLED);
}
return ret;
}
@@ -345,7 +378,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
_iwl_write32(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
@@ -537,7 +571,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
_iwl_write32(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 80b9e45d9b9..5ba5a4e9e49 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -63,6 +63,8 @@
#ifndef __iwl_eeprom_h__
#define __iwl_eeprom_h__
+#include <net/mac80211.h>
+
struct iwl_priv;
/*
@@ -256,6 +258,15 @@ struct iwl_eeprom_enhanced_txpwr {
#define EEPROM_5050_TX_POWER_VERSION (4)
#define EEPROM_5050_EEPROM_VERSION (0x21E)
+/* 1000 Specific */
+#define EEPROM_1000_EEPROM_VERSION (0x15C)
+
+/* 6x00 Specific */
+#define EEPROM_6000_EEPROM_VERSION (0x434)
+
+/* 6x50 Specific */
+#define EEPROM_6050_EEPROM_VERSION (0x532)
+
/* OTP */
/* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */
@@ -370,12 +381,10 @@ struct iwl_eeprom_calib_info {
#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
#define EEPROM_VERSION (2*0x44) /* 2 bytes */
#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */
-#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */
#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */
#define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */
-#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */
/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */
@@ -387,7 +396,12 @@ struct iwl_eeprom_calib_info {
#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0
#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1
-#define EEPROM_5000_RF_CFG_TYPE_MAX 0x3
+
+/* Radio Config for 5000 and up */
+#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0
+#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1
+#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2
+#define EEPROM_RF_CONFIG_TYPE_MAX 0x3
/*
* Per-channel regulatory data.
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 532c8d6cd8d..f2a60dc4109 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -92,6 +92,8 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(CALIBRATION_RES_NOTIFICATION);
IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
IWL_CMD(REPLY_TX_POWER_DBM_CMD);
+ IWL_CMD(TEMPERATURE_NOTIFICATION);
+ IWL_CMD(TX_ANT_CONFIGURATION_CMD);
default:
return "UNKNOWN";
@@ -103,17 +105,8 @@ EXPORT_SYMBOL(get_cmd_string);
static void iwl_generic_cmd_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
+ struct iwl_rx_packet *pkt)
{
- struct iwl_rx_packet *pkt = NULL;
-
- if (!skb) {
- IWL_ERR(priv, "Error: Response NULL in %s.\n",
- get_cmd_string(cmd->hdr.cmd));
- return;
- }
-
- pkt = (struct iwl_rx_packet *)skb->data;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
@@ -215,7 +208,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
ret = -EIO;
goto fail;
}
- if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) {
+ if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
IWL_ERR(priv, "Error: Response NULL in '%s'\n",
get_cmd_string(cmd->id));
ret = -EIO;
@@ -237,9 +230,9 @@ cancel:
~CMD_WANT_SKB;
}
fail:
- if (cmd->reply_skb) {
- dev_kfree_skb_any(cmd->reply_skb);
- cmd->reply_skb = NULL;
+ if (cmd->reply_page) {
+ free_pages(cmd->reply_page, priv->hw_params.rx_page_order);
+ cmd->reply_page = 0;
}
out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
@@ -272,7 +265,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
u8 id, u16 len, const void *data,
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb))
+ struct iwl_rx_packet *pkt))
{
struct iwl_host_cmd cmd = {
.id = id,
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index d30cb0275d1..0a078b08283 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -32,6 +32,7 @@
#include <linux/io.h>
#include "iwl-debug.h"
+#include "iwl-devtrace.h"
/*
* IO, register, and NIC memory access functions
@@ -61,7 +62,12 @@
*
*/
-#define _iwl_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs))
+static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
+{
+ trace_iwlwifi_dev_iowrite32(priv, ofs, val);
+ iowrite32(val, priv->hw_base + ofs);
+}
+
#ifdef CONFIG_IWLWIFI_DEBUG
static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
u32 ofs, u32 val)
@@ -75,7 +81,13 @@ static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val)
#endif
-#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs))
+static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs)
+{
+ u32 val = ioread32(priv->hw_base + ofs);
+ trace_iwlwifi_dev_ioread32(priv, ofs, val);
+ return val;
+}
+
#ifdef CONFIG_IWLWIFI_DEBUG
static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index f420c99e724..478c90511eb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -42,15 +42,11 @@
#include "iwl-core.h"
#include "iwl-io.h"
-#ifdef CONFIG_IWLWIFI_DEBUG
-static const char *led_type_str[] = {
- __stringify(IWL_LED_TRG_TX),
- __stringify(IWL_LED_TRG_RX),
- __stringify(IWL_LED_TRG_ASSOC),
- __stringify(IWL_LED_TRG_RADIO),
- NULL
-};
-#endif /* CONFIG_IWLWIFI_DEBUG */
+/* default: IWL_LED_BLINK(0) using blinking index table */
+static int led_mode;
+module_param(led_mode, int, S_IRUGO);
+MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), "
+ "(default 0)\n");
static const struct {
@@ -65,11 +61,11 @@ static const struct {
{70, 65, 65},
{50, 75, 75},
{20, 85, 85},
- {15, 95, 95 },
- {10, 110, 110},
- {5, 130, 130},
+ {10, 95, 95},
+ {5, 110, 110},
+ {1, 130, 130},
{0, 167, 167},
-/* SOLID_ON */
+ /* SOLID_ON */
{-1, IWL_LED_SOLID, 0}
};
@@ -78,191 +74,74 @@ static const struct {
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
-/* [0-256] -> [0..8] FIXME: we need [0..10] */
-static inline int iwl_brightness_to_idx(enum led_brightness brightness)
-{
- return fls(0x000000FF & (u32)brightness);
-}
-
-/* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
+/*
+ * Adjust led blink rate to compensate on a MAC Clock difference on every HW
+ * Led blink rate analysis showed an average deviation of 0% on 3945,
+ * 5% on 4965 HW and 20% on 5000 series and up.
+ * Need to compensate on the led on/off time per HW according to the deviation
+ * to achieve the desired led frequency
+ * The calculation is: (100-averageDeviation)/100 * blinkTime
+ * For code efficiency the calculation will be:
+ * compensation = (100 - averageDeviation) * 64 / 100
+ * NewBlinkTime = (compensation * BlinkTime) / 64
+ */
+static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
+ u8 time, u16 compensation)
{
- struct iwl_host_cmd cmd = {
- .id = REPLY_LEDS_CMD,
- .len = sizeof(struct iwl_led_cmd),
- .data = led_cmd,
- .flags = CMD_ASYNC,
- .callback = NULL,
- };
- u32 reg;
-
- reg = iwl_read32(priv, CSR_LED_REG);
- if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
- iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
+ if (!compensation) {
+ IWL_ERR(priv, "undefined blink compensation: "
+ "use pre-defined blinking time\n");
+ return time;
+ }
- return iwl_send_cmd(priv, &cmd);
+ return (u8)((time * compensation) >> 6);
}
/* Set led pattern command */
-static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
- unsigned int idx)
+static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx)
{
struct iwl_led_cmd led_cmd = {
- .id = led_id,
+ .id = IWL_LED_LINK,
.interval = IWL_DEF_LED_INTRVL
};
BUG_ON(idx > IWL_MAX_BLINK_TBL);
- led_cmd.on = blink_tbl[idx].on_time;
- led_cmd.off = blink_tbl[idx].off_time;
-
- return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-/* Set led register off */
-static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "led on %d\n", led_id);
- iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
- return 0;
-}
+ IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n",
+ priv->cfg->led_compensation);
+ led_cmd.on =
+ iwl_blink_compensation(priv, blink_tbl[idx].on_time,
+ priv->cfg->led_compensation);
+ led_cmd.off =
+ iwl_blink_compensation(priv, blink_tbl[idx].off_time,
+ priv->cfg->led_compensation);
-#if 0
-/* Set led on command */
-static int iwl_led_on(struct iwl_priv *priv, int led_id)
-{
- struct iwl_led_cmd led_cmd = {
- .id = led_id,
- .on = IWL_LED_SOLID,
- .off = 0,
- .interval = IWL_DEF_LED_INTRVL
- };
- return iwl_send_led_cmd(priv, &led_cmd);
+ return priv->cfg->ops->led->cmd(priv, &led_cmd);
}
-/* Set led off command */
-int iwl_led_off(struct iwl_priv *priv, int led_id)
+int iwl_led_start(struct iwl_priv *priv)
{
- struct iwl_led_cmd led_cmd = {
- .id = led_id,
- .on = 0,
- .off = 0,
- .interval = IWL_DEF_LED_INTRVL
- };
- IWL_DEBUG_LED(priv, "led off %d\n", led_id);
- return iwl_send_led_cmd(priv, &led_cmd);
+ return priv->cfg->ops->led->on(priv);
}
-#endif
-
+EXPORT_SYMBOL(iwl_led_start);
-/* Set led register off */
-static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "LED Reg off\n");
- iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
- return 0;
-}
-
-/*
- * Set led register in case of disassociation according to rfkill state
- */
-static int iwl_led_associate(struct iwl_priv *priv, int led_id)
+int iwl_led_associate(struct iwl_priv *priv)
{
IWL_DEBUG_LED(priv, "Associated\n");
- priv->allow_blinking = 1;
- return iwl_led_on_reg(priv, led_id);
-}
-static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
-{
- priv->allow_blinking = 0;
-
- return 0;
-}
-
-/*
- * brightness call back function for Tx/Rx LED
- */
-static int iwl_led_associated(struct iwl_priv *priv, int led_id)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
- !test_bit(STATUS_READY, &priv->status))
- return 0;
-
+ if (led_mode == IWL_LED_BLINK)
+ priv->allow_blinking = 1;
+ priv->last_blink_time = jiffies;
- /* start counting Tx/Rx bytes */
- if (!priv->last_blink_time && priv->allow_blinking)
- priv->last_blink_time = jiffies;
return 0;
}
-/*
- * brightness call back for association and radio
- */
-static void iwl_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+int iwl_led_disassociate(struct iwl_priv *priv)
{
- struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev);
- struct iwl_priv *priv = led->priv;
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
-
- IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n",
- led_type_str[led->type], brightness);
- switch (brightness) {
- case LED_FULL:
- if (led->led_on)
- led->led_on(priv, IWL_LED_LINK);
- break;
- case LED_OFF:
- if (led->led_off)
- led->led_off(priv, IWL_LED_LINK);
- break;
- default:
- if (led->led_pattern) {
- int idx = iwl_brightness_to_idx(brightness);
- led->led_pattern(priv, IWL_LED_LINK, idx);
- }
- break;
- }
-}
-
-
-
-/*
- * Register led class with the system
- */
-static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
- enum led_type type, u8 set_led,
- char *trigger)
-{
- struct device *device = wiphy_dev(priv->hw->wiphy);
- int ret;
-
- led->led_dev.name = led->name;
- led->led_dev.brightness_set = iwl_led_brightness_set;
- led->led_dev.default_trigger = trigger;
-
- led->priv = priv;
- led->type = type;
-
- ret = led_classdev_register(device, &led->led_dev);
- if (ret) {
- IWL_ERR(priv, "Error: failed to register led handler.\n");
- return ret;
- }
-
- led->registered = 1;
-
- if (set_led && led->led_on)
- led->led_on(priv, IWL_LED_LINK);
+ priv->allow_blinking = 0;
return 0;
}
-
/*
* calculate blink rate according to last second Tx/Rx activities
*/
@@ -288,7 +167,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
i = IWL_MAX_BLINK_TBL;
else
for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
- if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
+ if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
break;
IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i);
@@ -317,8 +196,7 @@ void iwl_leds_background(struct iwl_priv *priv)
priv->last_blink_time = 0;
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
- iwl_led_pattern(priv, IWL_LED_LINK,
- IWL_SOLID_BLINK_IDX);
+ iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX);
}
return;
}
@@ -331,111 +209,18 @@ void iwl_leds_background(struct iwl_priv *priv)
/* call only if blink rate change */
if (blink_idx != priv->last_blink_rate)
- iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
+ iwl_led_pattern(priv, blink_idx);
priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx;
}
+EXPORT_SYMBOL(iwl_leds_background);
-/* Register all led handler */
-int iwl_leds_register(struct iwl_priv *priv)
+void iwl_leds_init(struct iwl_priv *priv)
{
- char *trigger;
- int ret;
-
priv->last_blink_rate = 0;
priv->led_tpt = 0;
priv->last_blink_time = 0;
priv->allow_blinking = 0;
-
- trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RADIO].name,
- sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
- wiphy_name(priv->hw->wiphy));
-
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
- priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
- IWL_LED_TRG_RADIO, 1, trigger);
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
- sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
- IWL_LED_TRG_ASSOC, 0, trigger);
-
- /* for assoc always turn led on */
- priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate;
- priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate;
- priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RX].name,
- sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
- IWL_LED_TRG_RX, 0, trigger);
-
- priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
- priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_TX].name,
- sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
- IWL_LED_TRG_TX, 0, trigger);
-
- priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
- priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- return 0;
-
-exit_fail:
- iwl_leds_unregister(priv);
- return ret;
}
-EXPORT_SYMBOL(iwl_leds_register);
-
-/* unregister led class */
-static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led)
-{
- if (!led->registered)
- return;
-
- led_classdev_unregister(&led->led_dev);
-
- if (set_led)
- led->led_dev.brightness_set(&led->led_dev, LED_OFF);
- led->registered = 0;
-}
-
-/* Unregister all led handlers */
-void iwl_leds_unregister(struct iwl_priv *priv)
-{
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
-}
-EXPORT_SYMBOL(iwl_leds_unregister);
-
+EXPORT_SYMBOL(iwl_leds_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index ef9b174c37f..f47f053f02e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -30,9 +30,6 @@
struct iwl_priv;
-#ifdef CONFIG_IWLWIFI_LEDS
-#include <linux/leds.h>
-
#define IWL_LED_SOLID 11
#define IWL_LED_NAME_LEN 31
#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
@@ -47,38 +44,23 @@ enum led_type {
IWL_LED_TRG_RADIO,
IWL_LED_TRG_MAX,
};
-#endif
-
-#ifdef CONFIG_IWLWIFI_LEDS
-
-struct iwl_led {
- struct iwl_priv *priv;
- struct led_classdev led_dev;
- char name[32];
- int (*led_on) (struct iwl_priv *priv, int led_id);
- int (*led_off) (struct iwl_priv *priv, int led_id);
- int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx);
-
- enum led_type type;
- unsigned int registered;
+/*
+ * LED mode
+ * IWL_LED_BLINK: adjust led blink rate based on blink table
+ * IWL_LED_RF_STATE: turn LED on/off based on RF state
+ * LED ON = RF ON
+ * LED OFF = RF OFF
+ */
+enum iwl_led_mode {
+ IWL_LED_BLINK,
+ IWL_LED_RF_STATE,
};
-int iwl_leds_register(struct iwl_priv *priv);
-void iwl_leds_unregister(struct iwl_priv *priv);
+void iwl_leds_init(struct iwl_priv *priv);
void iwl_leds_background(struct iwl_priv *priv);
+int iwl_led_start(struct iwl_priv *priv);
+int iwl_led_associate(struct iwl_priv *priv);
+int iwl_led_disassociate(struct iwl_priv *priv);
-#else
-static inline int iwl_leds_register(struct iwl_priv *priv)
-{
- return 0;
-}
-static inline void iwl_leds_unregister(struct iwl_priv *priv)
-{
-}
-static inline void iwl_leds_background(struct iwl_priv *priv)
-{
-}
-
-#endif /* CONFIG_IWLWIFI_LEDS */
#endif /* __iwl_leds_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 60be976afff..9bce2c1625e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(no_sleep_autoadjust,
struct iwl_power_vec_entry {
struct iwl_powertable_cmd cmd;
- u8 no_dtim;
+ u8 no_dtim; /* number of skip dtim */
};
#define IWL_DTIM_RANGE_0_MAX 2
@@ -83,8 +83,9 @@ struct iwl_power_vec_entry {
cpu_to_le32(X4)}
/* default power management (not Tx power) table values */
/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
+/* DTIM 0 - 2 */
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
- {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
+ {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
@@ -93,15 +94,17 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
+/* DTIM 3 - 10 */
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
- {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
+ {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
};
/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
+/* DTIM 11 - */
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
@@ -115,13 +118,15 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
enum iwl_power_level lvl, int period)
{
const struct iwl_power_vec_entry *table;
- int max_sleep, i;
- bool skip;
+ int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
+ int i;
+ u8 skip;
+ u32 slp_itrvl;
table = range_2;
- if (period < IWL_DTIM_RANGE_1_MAX)
+ if (period <= IWL_DTIM_RANGE_1_MAX)
table = range_1;
- if (period < IWL_DTIM_RANGE_0_MAX)
+ if (period <= IWL_DTIM_RANGE_0_MAX)
table = range_0;
BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
@@ -129,34 +134,60 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
*cmd = table[lvl].cmd;
if (period == 0) {
- skip = false;
+ skip = 0;
period = 1;
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+ max_sleep[i] = 1;
+
} else {
- skip = !!table[lvl].no_dtim;
+ skip = table[lvl].no_dtim;
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+ max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]);
+ max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1;
}
- if (skip) {
- __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
- max_sleep = le32_to_cpu(slp_itrvl);
- if (max_sleep == 0xFF)
- max_sleep = period * (skip + 1);
- else if (max_sleep > period)
- max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+ slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+ /* figure out the listen interval based on dtim period and skip */
+ if (slp_itrvl == 0xFF)
+ cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+ cpu_to_le32(period * (skip + 1));
+
+ slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+ if (slp_itrvl > period)
+ cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+ cpu_to_le32((slp_itrvl / period) * period);
+
+ if (skip)
cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
- } else {
- max_sleep = period;
+ else
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
- }
- for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
- if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
- cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+ slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+ if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
+ cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+ cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL);
+
+ /* enforce max sleep interval */
+ for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) >
+ (max_sleep[i] * period))
+ cmd->sleep_interval[i] =
+ cpu_to_le32(max_sleep[i] * period);
+ if (i != (IWL_POWER_VEC_SIZE - 1)) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) >
+ le32_to_cpu(cmd->sleep_interval[i+1]))
+ cmd->sleep_interval[i] =
+ cmd->sleep_interval[i+1];
+ }
+ }
if (priv->power_data.pci_pm)
cmd->flags |= IWL_POWER_PCI_PM_MSK;
else
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+ IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
+ skip, period);
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}
@@ -165,26 +196,26 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
*=============================================================================
* Condition Nxt State Condition Nxt State Condition Nxt State
*-----------------------------------------------------------------------------
- * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
- * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
- * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
+ * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
+ * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
+ * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
*=============================================================================
*/
static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
- {IWL_TI_1, 105, CT_KILL_THRESHOLD},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+ {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
};
static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
- {IWL_TI_2, 110, CT_KILL_THRESHOLD},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+ {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
};
static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
+ {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
};
static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
@@ -294,6 +325,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
if (priv->cfg->broken_powersave)
iwl_power_sleep_cam_cmd(priv, &cmd);
+ else if (priv->cfg->supports_idle &&
+ priv->hw->conf.flags & IEEE80211_CONF_IDLE)
+ iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
else if (tt->state >= IWL_TI_1)
iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
else if (!enabled)
@@ -348,6 +382,23 @@ bool iwl_ht_enabled(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_ht_enabled);
+bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
+{
+ s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+ bool within_margin = false;
+
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+ temp = KELVIN_TO_CELSIUS(priv->temperature);
+
+ if (!priv->thermal_throttle.advanced_tt)
+ within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+ CT_KILL_THRESHOLD_LEGACY) ? true : false;
+ else
+ within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+ CT_KILL_THRESHOLD) ? true : false;
+ return within_margin;
+}
+
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
{
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
@@ -372,6 +423,7 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
}
#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
+#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
/*
* toggle the bit to wake up uCode and check the temperature
@@ -409,6 +461,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
/* Reschedule the ct_kill timer to occur in
* CT_KILL_EXIT_DURATION seconds to ensure we get a
* thermal update */
+ IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
CT_KILL_EXIT_DURATION * HZ);
}
@@ -432,6 +485,33 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
}
}
+static void iwl_tt_ready_for_ct_kill(unsigned long data)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)data;
+ struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ /* temperature timer expired, ready to go into CT_KILL state */
+ if (tt->state != IWL_TI_CT_KILL) {
+ IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n");
+ tt->state = IWL_TI_CT_KILL;
+ set_bit(STATUS_CT_KILL, &priv->status);
+ iwl_perform_ct_kill_task(priv, true);
+ }
+}
+
+static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
+{
+ IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
+ /* make request to retrieve statistics information */
+ iwl_send_statistics_request(priv, 0);
+ /* Reschedule the ct_kill wait timer */
+ mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
+ jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
+}
+
#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
@@ -445,7 +525,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
* Throttle early enough to lower the power consumption before
* drastic steps are needed
*/
-static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
{
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
enum iwl_tt_state old_state;
@@ -474,6 +554,8 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
#ifdef CONFIG_IWLWIFI_DEBUG
tt->tt_previous_temp = temp;
#endif
+ /* stop ct_kill_waiting_tm timer */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
if (tt->state != old_state) {
switch (tt->state) {
case IWL_TI_0:
@@ -494,17 +576,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
break;
}
mutex_lock(&priv->mutex);
- if (iwl_power_update_mode(priv, true)) {
+ if (old_state == IWL_TI_CT_KILL)
+ clear_bit(STATUS_CT_KILL, &priv->status);
+ if (tt->state != IWL_TI_CT_KILL &&
+ iwl_power_update_mode(priv, true)) {
/* TT state not updated
* try again during next temperature read
*/
+ if (old_state == IWL_TI_CT_KILL)
+ set_bit(STATUS_CT_KILL, &priv->status);
tt->state = old_state;
IWL_ERR(priv, "Cannot update power mode, "
"TT state not updated\n");
} else {
- if (tt->state == IWL_TI_CT_KILL)
- iwl_perform_ct_kill_task(priv, true);
- else if (old_state == IWL_TI_CT_KILL &&
+ if (tt->state == IWL_TI_CT_KILL) {
+ if (force) {
+ set_bit(STATUS_CT_KILL, &priv->status);
+ iwl_perform_ct_kill_task(priv, true);
+ } else {
+ iwl_prepare_ct_kill_task(priv);
+ tt->state = old_state;
+ }
+ } else if (old_state == IWL_TI_CT_KILL &&
tt->state != IWL_TI_CT_KILL)
iwl_perform_ct_kill_task(priv, false);
IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
@@ -531,13 +624,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
*=============================================================================
* Condition Nxt State Condition Nxt State Condition Nxt State
*-----------------------------------------------------------------------------
- * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
- * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
- * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
+ * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
+ * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
+ * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
*=============================================================================
*/
-static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
{
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
int i;
@@ -582,6 +675,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
break;
}
}
+ /* stop ct_kill_waiting_tm timer */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
if (changed) {
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
@@ -613,12 +708,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
iwl_set_rxon_ht(priv, &priv->current_ht_config);
}
mutex_lock(&priv->mutex);
- if (iwl_power_update_mode(priv, true)) {
+ if (old_state == IWL_TI_CT_KILL)
+ clear_bit(STATUS_CT_KILL, &priv->status);
+ if (tt->state != IWL_TI_CT_KILL &&
+ iwl_power_update_mode(priv, true)) {
/* TT state not updated
* try again during next temperature read
*/
IWL_ERR(priv, "Cannot update power mode, "
"TT state not updated\n");
+ if (old_state == IWL_TI_CT_KILL)
+ set_bit(STATUS_CT_KILL, &priv->status);
tt->state = old_state;
} else {
IWL_DEBUG_POWER(priv,
@@ -626,9 +726,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
tt->state);
if (old_state != IWL_TI_CT_KILL &&
tt->state == IWL_TI_CT_KILL) {
- IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n");
- iwl_perform_ct_kill_task(priv, true);
-
+ if (force) {
+ IWL_DEBUG_POWER(priv,
+ "Enter IWL_TI_CT_KILL\n");
+ set_bit(STATUS_CT_KILL, &priv->status);
+ iwl_perform_ct_kill_task(priv, true);
+ } else {
+ iwl_prepare_ct_kill_task(priv);
+ tt->state = old_state;
+ }
} else if (old_state == IWL_TI_CT_KILL &&
tt->state != IWL_TI_CT_KILL) {
IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
@@ -665,10 +771,11 @@ static void iwl_bg_ct_enter(struct work_struct *work)
"- ucode going to sleep!\n");
if (!priv->thermal_throttle.advanced_tt)
iwl_legacy_tt_handler(priv,
- IWL_MINIMAL_POWER_THRESHOLD);
+ IWL_MINIMAL_POWER_THRESHOLD,
+ true);
else
iwl_advance_tt_handler(priv,
- CT_KILL_THRESHOLD + 1);
+ CT_KILL_THRESHOLD + 1, true);
}
}
@@ -695,11 +802,18 @@ static void iwl_bg_ct_exit(struct work_struct *work)
IWL_ERR(priv,
"Device temperature below critical"
"- ucode awake!\n");
+ /*
+ * exit from CT_KILL state
+ * reset the current temperature reading
+ */
+ priv->temperature = 0;
if (!priv->thermal_throttle.advanced_tt)
iwl_legacy_tt_handler(priv,
- IWL_REDUCED_PERFORMANCE_THRESHOLD_2);
+ IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
+ true);
else
- iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
+ iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
+ true);
}
}
@@ -735,9 +849,9 @@ static void iwl_bg_tt_work(struct work_struct *work)
temp = KELVIN_TO_CELSIUS(priv->temperature);
if (!priv->thermal_throttle.advanced_tt)
- iwl_legacy_tt_handler(priv, temp);
+ iwl_legacy_tt_handler(priv, temp, false);
else
- iwl_advance_tt_handler(priv, temp);
+ iwl_advance_tt_handler(priv, temp, false);
}
void iwl_tt_handler(struct iwl_priv *priv)
@@ -768,16 +882,18 @@ void iwl_tt_initialize(struct iwl_priv *priv)
tt->state = IWL_TI_0;
init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
- priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill;
-
+ priv->thermal_throttle.ct_kill_exit_tm.function =
+ iwl_tt_check_exit_ct_kill;
+ init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
+ priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv;
+ priv->thermal_throttle.ct_kill_waiting_tm.function =
+ iwl_tt_ready_for_ct_kill;
/* setup deferred ct kill work */
INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
- case CSR_HW_REV_TYPE_6x00:
- case CSR_HW_REV_TYPE_6x50:
+ if (priv->cfg->adv_thermal_throttle) {
IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
IWL_TI_STATE_MAX, GFP_KERNEL);
@@ -810,11 +926,9 @@ void iwl_tt_initialize(struct iwl_priv *priv)
&restriction_range[0], size);
priv->thermal_throttle.advanced_tt = true;
}
- break;
- default:
+ } else {
IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
priv->thermal_throttle.advanced_tt = false;
- break;
}
}
EXPORT_SYMBOL(iwl_tt_initialize);
@@ -826,6 +940,8 @@ void iwl_tt_exit(struct iwl_priv *priv)
/* stop ct_kill_exit_tm timer if activated */
del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+ /* stop ct_kill_waiting_tm timer if activated */
+ del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
cancel_work_sync(&priv->tt_work);
cancel_work_sync(&priv->ct_enter);
cancel_work_sync(&priv->ct_exit);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index df6f6a49712..310c32e8f69 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -33,6 +33,7 @@
#define IWL_ABSOLUTE_ZERO 0
#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
#define IWL_TT_INCREASE_MARGIN 5
+#define IWL_TT_CT_KILL_MARGIN 3
enum iwl_antenna_ok {
IWL_ANT_OK_NONE,
@@ -110,6 +111,7 @@ struct iwl_tt_mgmt {
struct iwl_tt_restriction *restriction;
struct iwl_tt_trans *transaction;
struct timer_list ct_kill_exit_tm;
+ struct timer_list ct_kill_waiting_tm;
};
enum iwl_power_level {
@@ -129,6 +131,7 @@ struct iwl_power_mgr {
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
bool iwl_ht_enabled(struct iwl_priv *priv);
+bool iwl_within_ct_kill_margin(struct iwl_priv *priv);
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 493626bcd3e..e5339c9ad13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -200,7 +200,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */
- rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->aligned_dma_addr);
+ rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--;
@@ -239,8 +239,9 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
- struct sk_buff *skb;
+ struct page *page;
unsigned long flags;
+ gfp_t gfp_mask = priority;
while (1) {
spin_lock_irqsave(&rxq->lock, flags);
@@ -251,30 +252,35 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags);
if (rxq->free_count > RX_LOW_WATERMARK)
- priority |= __GFP_NOWARN;
- /* Alloc a new receive buffer */
- skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
- priority);
+ gfp_mask |= __GFP_NOWARN;
+
+ if (priv->hw_params.rx_page_order > 0)
+ gfp_mask |= __GFP_COMP;
- if (!skb) {
+ /* Alloc a new receive buffer */
+ page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
+ if (!page) {
if (net_ratelimit())
- IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
+ IWL_DEBUG_INFO(priv, "alloc_pages failed, "
+ "order: %d\n",
+ priv->hw_params.rx_page_order);
+
if ((rxq->free_count <= RX_LOW_WATERMARK) &&
net_ratelimit())
- IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
+ IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL",
rxq->free_count);
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
- break;
+ return;
}
spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
- dev_kfree_skb_any(skb);
+ __free_pages(page, priv->hw_params.rx_page_order);
return;
}
element = rxq->rx_used.next;
@@ -283,24 +289,21 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags);
- rxb->skb = skb;
- /* Get physical address of RB/SKB */
- rxb->real_dma_addr = pci_map_single(
- priv->pci_dev,
- rxb->skb->data,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
+ rxb->page = page;
+ /* Get physical address of the RB */
+ rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
/* dma address must be no more than 36 bits */
- BUG_ON(rxb->real_dma_addr & ~DMA_BIT_MASK(36));
+ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
/* and also 256 byte aligned! */
- rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
- skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
+ BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
- priv->alloc_rxb_skb++;
+ priv->alloc_rxb_page++;
spin_unlock_irqrestore(&rxq->lock, flags);
}
@@ -336,12 +339,14 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
+ priv->alloc_rxb_page--;
}
}
@@ -405,14 +410,14 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
- priv->alloc_rxb_skb--;
- dev_kfree_skb(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_page--;
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
}
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
}
@@ -491,7 +496,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_missed_beacon_notif *missed_beacon;
missed_beacon = &pkt->u.missed_beacon;
@@ -548,13 +553,51 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
priv->last_rx_noise);
}
+#ifdef CONFIG_IWLWIFI_DEBUG
+/*
+ * based on the assumption of all statistics counter are in DWORD
+ * FIXME: This function is for debugging, do not deal with
+ * the case of counters roll-over.
+ */
+static void iwl_accumulative_statistics(struct iwl_priv *priv,
+ __le32 *stats)
+{
+ int i;
+ __le32 *prev_stats;
+ u32 *accum_stats;
+
+ prev_stats = (__le32 *)&priv->statistics;
+ accum_stats = (u32 *)&priv->accum_statistics;
+
+ for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
+ i += sizeof(__le32), stats++, prev_stats++, accum_stats++)
+ if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats))
+ *accum_stats += (le32_to_cpu(*stats) -
+ le32_to_cpu(*prev_stats));
+
+ /* reset accumulative statistics for "no-counter" type statistics */
+ priv->accum_statistics.general.temperature =
+ priv->statistics.general.temperature;
+ priv->accum_statistics.general.temperature_m =
+ priv->statistics.general.temperature_m;
+ priv->accum_statistics.general.ttl_timestamp =
+ priv->statistics.general.ttl_timestamp;
+ priv->accum_statistics.tx.tx_power.ant_a =
+ priv->statistics.tx.tx_power.ant_a;
+ priv->accum_statistics.tx.tx_power.ant_b =
+ priv->statistics.tx.tx_power.ant_b;
+ priv->accum_statistics.tx.tx_power.ant_c =
+ priv->statistics.tx.tx_power.ant_c;
+}
+#endif
+
#define REG_RECALIB_PERIOD (60)
void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
int change;
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(priv->statistics),
@@ -566,6 +609,9 @@ void iwl_rx_statistics(struct iwl_priv *priv,
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+#ifdef CONFIG_IWLWIFI_DEBUG
+ iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+#endif
memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
set_bit(STATUS_STATISTICS, &priv->status);
@@ -582,9 +628,6 @@ void iwl_rx_statistics(struct iwl_priv *priv,
iwl_rx_calc_noise(priv);
queue_work(priv->workqueue, &priv->run_time_calib_work);
}
-
- iwl_leds_background(priv);
-
if (priv->cfg->ops->lib->temp_ops.temperature && change)
priv->cfg->ops->lib->temp_ops.temperature(priv);
}
@@ -878,6 +921,10 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats)
{
+ struct sk_buff *skb;
+ int ret = 0;
+ __le16 fc = hdr->frame_control;
+
/* We only process data packets if the interface is open */
if (unlikely(!priv->is_open)) {
IWL_DEBUG_DROP_LIMIT(priv,
@@ -890,15 +937,43 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
- /* Resize SKB from mac header to end of packet */
- skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data);
- skb_put(rxb->skb, len);
+ skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
+ if (!skb) {
+ IWL_ERR(priv, "alloc_skb failed\n");
+ return;
+ }
+
+ skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
+
+ /* mac80211 currently doesn't support paged SKB. Convert it to
+ * linear SKB for management frame and data frame requires
+ * software decryption or software defragementation. */
+ if (ieee80211_is_mgmt(fc) ||
+ ieee80211_has_protected(fc) ||
+ ieee80211_has_morefrags(fc) ||
+ le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
+ ret = skb_linearize(skb);
+ else
+ ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
+ 0 : -ENOMEM;
+
+ if (ret) {
+ kfree_skb(skb);
+ goto out;
+ }
+
+ /*
+ * XXX: We cannot touch the page and its virtual memory (hdr) after
+ * here. It might have already been freed by the above skb change.
+ */
+
+ iwl_update_stats(priv, false, fc, len);
+ memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
- iwl_update_stats(priv, false, hdr->frame_control, len);
- memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
- ieee80211_rx_irqsafe(priv->hw, rxb->skb);
- priv->alloc_rxb_skb--;
- rxb->skb = NULL;
+ ieee80211_rx(priv->hw, skb);
+ out:
+ priv->alloc_rxb_page--;
+ rxb->page = NULL;
}
/* This is necessary only for a number of statistics, see the caller. */
@@ -926,7 +1001,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
{
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rx_phy_res *phy_res;
__le32 rx_pkt_status;
struct iwl4965_rx_mpdu_res_start *amsdu;
@@ -1087,7 +1162,7 @@ EXPORT_SYMBOL(iwl_rx_reply_rx);
void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
priv->last_phy_res[0] = 1;
memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
sizeof(struct iwl_rx_phy_res));
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 4f3a108fa99..4fca65a2fe9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -27,7 +27,6 @@
*****************************************************************************/
#include <linux/types.h>
#include <linux/etherdevice.h>
-#include <net/lib80211.h>
#include <net/mac80211.h>
#include "iwl-eeprom.h"
@@ -112,7 +111,7 @@ EXPORT_SYMBOL(iwl_scan_cancel_timeout);
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
int ret = 0;
- struct iwl_rx_packet *res;
+ struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_ABORT_CMD,
.flags = CMD_WANT_SKB,
@@ -132,21 +131,21 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
return ret;
}
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->u.status != CAN_ABORT_STATUS) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->u.status != CAN_ABORT_STATUS) {
/* The scan abort will return 1 for success or
* 2 for "failure". A failure condition can be
* due to simply not being in an active scan which
* can occur if we send the scan abort before we
* the microcode has notified us that a scan is
* completed. */
- IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", res->u.status);
+ IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status);
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
clear_bit(STATUS_SCAN_HW, &priv->status);
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret;
}
@@ -156,7 +155,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanreq_notification *notif =
(struct iwl_scanreq_notification *)pkt->u.raw;
@@ -168,7 +167,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanstart_notification *notif =
(struct iwl_scanstart_notification *)pkt->u.raw;
priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
@@ -187,7 +186,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanresults_notification *notif =
(struct iwl_scanresults_notification *)pkt->u.raw;
@@ -214,7 +213,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
index 022bcf11573..1ea5cd345fe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
@@ -177,7 +177,7 @@ static int iwl_get_measurement(struct iwl_priv *priv,
static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
if (!report->state) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index c6633fec821..dc74c16d36a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -99,32 +99,25 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
static void iwl_add_sta_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
+ struct iwl_rx_packet *pkt)
{
- struct iwl_rx_packet *res = NULL;
struct iwl_addsta_cmd *addsta =
(struct iwl_addsta_cmd *)cmd->cmd.payload;
u8 sta_id = addsta->sta.sta_id;
- if (!skb) {
- IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
- return;
- }
-
- res = (struct iwl_rx_packet *)skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
return;
}
- switch (res->u.add_sta.status) {
+ switch (pkt->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK:
iwl_sta_ucode_activate(priv, sta_id);
/* fall through */
default:
IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
- res->u.add_sta.status);
+ pkt->u.add_sta.status);
break;
}
}
@@ -132,7 +125,7 @@ static void iwl_add_sta_callback(struct iwl_priv *priv,
int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags)
{
- struct iwl_rx_packet *res = NULL;
+ struct iwl_rx_packet *pkt = NULL;
int ret = 0;
u8 data[sizeof(*sta)];
struct iwl_host_cmd cmd = {
@@ -152,15 +145,15 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
ret = -EIO;
}
if (ret == 0) {
- switch (res->u.add_sta.status) {
+ switch (pkt->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK:
iwl_sta_ucode_activate(priv, sta->sta.sta_id);
IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
@@ -172,8 +165,8 @@ int iwl_send_add_sta(struct iwl_priv *priv,
}
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret;
}
@@ -324,26 +317,19 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
static void iwl_remove_sta_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
+ struct iwl_rx_packet *pkt)
{
- struct iwl_rx_packet *res = NULL;
struct iwl_rem_sta_cmd *rm_sta =
- (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
+ (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
const char *addr = rm_sta->addr;
- if (!skb) {
- IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
- return;
- }
-
- res = (struct iwl_rx_packet *)skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
return;
}
- switch (res->u.rem_sta.status) {
+ switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr);
break;
@@ -356,7 +342,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv,
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
u8 flags)
{
- struct iwl_rx_packet *res = NULL;
+ struct iwl_rx_packet *pkt;
int ret;
struct iwl_rem_sta_cmd rm_sta_cmd;
@@ -381,15 +367,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
ret = -EIO;
}
if (!ret) {
- switch (res->u.rem_sta.status) {
+ switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr);
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
@@ -401,8 +387,8 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
}
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index c1890754470..8ae4c9b614e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -131,7 +131,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
- int i, len;
+ int i;
if (q->n_bd == 0)
return;
@@ -141,8 +141,6 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
- len = sizeof(struct iwl_device_cmd) * q->n_window;
-
/* De-alloc array of command/tx buffers */
for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
kfree(txq->cmd[i]);
@@ -180,14 +178,11 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
- int i, len;
+ int i;
if (q->n_bd == 0)
return;
- len = sizeof(struct iwl_device_cmd) * q->n_window;
- len += IWL_MAX_SCAN_SIZE;
-
/* De-alloc array of command/tx buffers */
for (i = 0; i <= TFD_CMD_SLOTS; i++)
kfree(txq->cmd[i]);
@@ -405,15 +400,19 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- if (txq_id == IWL_CMD_QUEUE_NUM)
- iwl_cmd_queue_free(priv);
- else
- iwl_tx_queue_free(priv, txq_id);
-
+ if (priv->txq)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
+ txq_id++)
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ iwl_cmd_queue_free(priv);
+ else
+ iwl_tx_queue_free(priv, txq_id);
iwl_free_dma_ptr(priv, &priv->kw);
iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
+
+ /* free tx queue structure */
+ iwl_free_txq_mem(priv);
}
EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
@@ -445,6 +444,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
IWL_ERR(priv, "Keep Warm allocation failed\n");
goto error_kw;
}
+
+ /* allocate tx queue structure */
+ ret = iwl_alloc_txq_mem(priv);
+ if (ret)
+ goto error;
+
spin_lock_irqsave(&priv->lock, flags);
/* Turn off all Tx DMA fifos */
@@ -581,9 +586,7 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
u8 rate_plcp;
/* Set retry limit on DATA packets and Probe Responses*/
- if (priv->data_retry_limit != -1)
- data_retry_limit = priv->data_retry_limit;
- else if (ieee80211_is_probe_resp(fc))
+ if (ieee80211_is_probe_resp(fc))
data_retry_limit = 3;
else
data_retry_limit = IWL_DEFAULT_TX_RETRY;
@@ -709,7 +712,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
- u16 len, len_org;
+ u16 len, len_org, firstlen, secondlen;
u16 seq_number = 0;
__le16 fc;
u8 hdr_len;
@@ -842,7 +845,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
sizeof(struct iwl_cmd_header) + hdr_len;
len_org = len;
- len = (len + 3) & ~3;
+ firstlen = len = (len + 3) & ~3;
if (len_org != len)
len_org = 1;
@@ -876,7 +879,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
- len = skb->len - hdr_len;
+ secondlen = len = skb->len - hdr_len;
if (len) {
phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
len, PCI_DMA_TODEVICE);
@@ -910,6 +913,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
len, PCI_DMA_BIDIRECTIONAL);
+ trace_iwlwifi_dev_tx(priv,
+ &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+ sizeof(struct iwl_tfd),
+ &out_cmd->hdr, firstlen,
+ skb->data + hdr_len, secondlen);
+
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
ret = iwl_txq_update_write_ptr(priv, txq);
@@ -969,13 +978,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
!(cmd->flags & CMD_SIZE_HUGE));
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
+ if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
+ IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n");
return -EIO;
}
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERR(priv, "No space for Tx\n");
+ if (iwl_within_ct_kill_margin(priv))
+ iwl_tt_enter_ct_kill(priv);
+ else {
+ IWL_ERR(priv, "Restarting adapter due to queue full\n");
+ queue_work(priv->workqueue, &priv->restart);
+ }
return -ENOSPC;
}
@@ -1038,6 +1053,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
pci_unmap_addr_set(out_meta, mapping, phys_addr);
pci_unmap_len_set(out_meta, len, fix_size);
+ trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
+
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
phys_addr, fix_size, 1,
U32_PAD(cmd->len));
@@ -1131,7 +1148,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
*/
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -1158,10 +1175,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
/* Input error checking is done when commands are added to queue. */
if (meta->flags & CMD_WANT_SKB) {
- meta->source->reply_skb = rxb->skb;
- rxb->skb = NULL;
+ meta->source->reply_page = (unsigned long)rxb_addr(rxb);
+ rxb->page = NULL;
} else if (meta->callback)
- meta->callback(priv, cmd, rxb->skb);
+ meta->callback(priv, cmd, pkt);
iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
@@ -1400,7 +1417,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
memset(&info->status, 0, sizeof(info->status));
- info->flags = IEEE80211_TX_STAT_ACK;
+ info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_map = successes;
info->status.ampdu_ack_len = agg->frame_count;
@@ -1420,7 +1437,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
struct iwl_tx_queue *txq = NULL;
struct iwl_ht_agg *agg;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 837a193221c..bfd7f497157 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -41,7 +41,6 @@
#include <linux/if_arp.h>
#include <net/ieee80211_radiotap.h>
-#include <net/lib80211.h>
#include <net/mac80211.h>
#include <asm/div64.h>
@@ -89,7 +88,6 @@ MODULE_LICENSE("GPL");
/* module parameters */
struct iwl_mod_params iwl3945_mod_params = {
- .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -367,13 +365,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct sk_buff *skb_frag,
int sta_id)
{
- struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
+ struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
switch (keyinfo->alg) {
case ALG_CCMP:
- tx->sec_ctl = TX_CMD_SEC_CCM;
- memcpy(tx->key, keyinfo->key, keyinfo->keylen);
+ tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+ memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
break;
@@ -381,13 +379,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break;
case ALG_WEP:
- tx->sec_ctl = TX_CMD_SEC_WEP |
+ tx_cmd->sec_ctl = TX_CMD_SEC_WEP |
(info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
if (keyinfo->keylen == 13)
- tx->sec_ctl |= TX_CMD_SEC_KEY128;
+ tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
- memcpy(&tx->key[3], keyinfo->key, keyinfo->keylen);
+ memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
"with key %d\n", info->control.hw_key->hw_key_idx);
@@ -407,12 +405,11 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, u8 std_id)
{
- struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
- __le32 tx_flags = tx->tx_flags;
+ struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
+ __le32 tx_flags = tx_cmd->tx_flags;
__le16 fc = hdr->frame_control;
- u8 rc_flags = info->control.rates[0].flags;
- tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
tx_flags |= TX_CMD_FLG_ACK_MSK;
if (ieee80211_is_mgmt(fc))
@@ -425,25 +422,19 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- tx->sta_id = std_id;
+ tx_cmd->sta_id = std_id;
if (ieee80211_has_morefrags(fc))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
if (ieee80211_is_data_qos(fc)) {
u8 *qc = ieee80211_get_qos_ctl(hdr);
- tx->tid_tspec = qc[0] & 0xf;
+ tx_cmd->tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
} else {
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- tx_flags |= TX_CMD_FLG_RTS_MSK;
- tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
+ priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
@@ -451,19 +442,16 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
if (ieee80211_is_mgmt(fc)) {
if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
- tx->timeout.pm_frame_timeout = cpu_to_le16(3);
+ tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
else
- tx->timeout.pm_frame_timeout = cpu_to_le16(2);
+ tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
} else {
- tx->timeout.pm_frame_timeout = 0;
-#ifdef CONFIG_IWLWIFI_LEDS
- priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len);
-#endif
+ tx_cmd->timeout.pm_frame_timeout = 0;
}
- tx->driver_txop = 0;
- tx->tx_flags = tx_flags;
- tx->next_frame_len = 0;
+ tx_cmd->driver_txop = 0;
+ tx_cmd->tx_flags = tx_flags;
+ tx_cmd->next_frame_len = 0;
}
/*
@@ -473,7 +461,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct iwl3945_tx_cmd *tx;
+ struct iwl3945_tx_cmd *tx_cmd;
struct iwl_tx_queue *txq = NULL;
struct iwl_queue *q = NULL;
struct iwl_device_cmd *out_cmd;
@@ -572,9 +560,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
- tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
+ tx_cmd = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
- memset(tx, 0, sizeof(*tx));
+ memset(tx_cmd, 0, sizeof(*tx_cmd));
/*
* Set up the Tx-command (not MAC!) header.
@@ -587,7 +575,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
INDEX_TO_SEQ(q->write_ptr)));
/* Copy MAC header from skb into command buffer */
- memcpy(tx->hdr, hdr, hdr_len);
+ memcpy(tx_cmd->hdr, hdr, hdr_len);
if (info->control.hw_key)
@@ -601,12 +589,12 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Total # bytes to be transmitted */
len = (u16)skb->len;
- tx->len = cpu_to_le16(len);
+ tx_cmd->len = cpu_to_le16(len);
iwl_dbg_log_tx_data_frame(priv, len, hdr);
iwl_update_stats(priv, true, fc, len);
- tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
- tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
+ tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
+ tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
@@ -619,9 +607,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
le16_to_cpu(out_cmd->hdr.sequence));
- IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags));
- iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
+ IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
+ iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd));
+ iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr,
ieee80211_hdrlen(fc));
/*
@@ -757,7 +745,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
u8 type)
{
struct iwl_spectrum_cmd spectrum;
- struct iwl_rx_packet *res;
+ struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
.data = (void *)&spectrum,
@@ -802,18 +790,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
rc = -EIO;
}
- spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+ spectrum_resp_status = le16_to_cpu(pkt->u.spectrum.status);
switch (spectrum_resp_status) {
case 0: /* Command will be handled */
- if (res->u.spectrum.id != 0xff) {
+ if (pkt->u.spectrum.id != 0xff) {
IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n",
- res->u.spectrum.id);
+ pkt->u.spectrum.id);
priv->measurement_status &= ~MEASUREMENT_READY;
}
priv->measurement_status |= MEASUREMENT_ACTIVE;
@@ -825,7 +813,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
break;
}
- dev_kfree_skb_any(cmd.reply_skb);
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return rc;
}
@@ -834,7 +822,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
static void iwl3945_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_alive_resp *palive;
struct delayed_work *pwork;
@@ -871,7 +859,7 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
#endif
IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
@@ -907,7 +895,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
u8 rate = beacon->beacon_notify_hdr.rate;
@@ -930,7 +918,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
@@ -1094,7 +1082,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */
- rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->real_dma_addr);
+ rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->page_dma);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--;
@@ -1134,8 +1122,9 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
- struct sk_buff *skb;
+ struct page *page;
unsigned long flags;
+ gfp_t gfp_mask = priority;
while (1) {
spin_lock_irqsave(&rxq->lock, flags);
@@ -1147,10 +1136,14 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags);
if (rxq->free_count > RX_LOW_WATERMARK)
- priority |= __GFP_NOWARN;
+ gfp_mask |= __GFP_NOWARN;
+
+ if (priv->hw_params.rx_page_order > 0)
+ gfp_mask |= __GFP_COMP;
+
/* Alloc a new receive buffer */
- skb = alloc_skb(priv->hw_params.rx_buf_size, priority);
- if (!skb) {
+ page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
+ if (!page) {
if (net_ratelimit())
IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
if ((rxq->free_count <= RX_LOW_WATERMARK) &&
@@ -1167,7 +1160,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
- dev_kfree_skb_any(skb);
+ __free_pages(page, priv->hw_params.rx_page_order);
return;
}
element = rxq->rx_used.next;
@@ -1175,26 +1168,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
list_del(element);
spin_unlock_irqrestore(&rxq->lock, flags);
- rxb->skb = skb;
-
- /* If radiotap head is required, reserve some headroom here.
- * The physical head count is a variable rx_stats->phy_count.
- * We reserve 4 bytes here. Plus these extra bytes, the
- * headroom of the physical head should be enough for the
- * radiotap head that iwl3945 supported. See iwl3945_rt.
- */
- skb_reserve(rxb->skb, 4);
-
+ rxb->page = page;
/* Get physical address of RB/SKB */
- rxb->real_dma_addr = pci_map_single(priv->pci_dev,
- rxb->skb->data,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
+ rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
spin_lock_irqsave(&rxq->lock, flags);
+
list_add_tail(&rxb->list, &rxq->rx_free);
- priv->alloc_rxb_skb++;
rxq->free_count++;
+ priv->alloc_rxb_page++;
+
spin_unlock_irqrestore(&rxq->lock, flags);
}
}
@@ -1210,14 +1195,14 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- priv->alloc_rxb_skb--;
- dev_kfree_skb(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_page--;
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
}
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
}
@@ -1225,8 +1210,8 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
- rxq->free_count = 0;
rxq->write_actual = 0;
+ rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
@@ -1259,12 +1244,14 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
{
int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
+ priv->alloc_rxb_page--;
}
}
@@ -1380,7 +1367,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
i = rxq->read;
/* calculate total frames need to be restock after handling RX */
- total_empty = r - priv->rxq.write_actual;
+ total_empty = r - rxq->write_actual;
if (total_empty < 0)
total_empty += RX_QUEUE_SIZE;
@@ -1400,10 +1387,13 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL;
- pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ pci_unmap_page(priv->pci_dev, rxb->page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ pkt = rxb_addr(rxb);
+
+ trace_iwlwifi_dev_rx(priv, pkt,
+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
@@ -1421,44 +1411,55 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
if (priv->rx_handlers[pkt->hdr.cmd]) {
IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i,
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
- priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
} else {
/* No handling needed */
- IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n",
+ IWL_DEBUG_RX(priv,
+ "r %d i %d No handler needed for %s, 0x%02x\n",
r, i, get_cmd_string(pkt->hdr.cmd),
pkt->hdr.cmd);
}
+ /*
+ * XXX: After here, we should always check rxb->page
+ * against NULL before touching it or its virtual
+ * memory (pkt). Because some rx_handler might have
+ * already taken or freed the pages.
+ */
+
if (reclaim) {
- /* Invoke any callbacks, transfer the skb to caller, and
- * fire off the (possibly) blocking iwl_send_cmd()
+ /* Invoke any callbacks, transfer the buffer to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
* as we reclaim the driver command queue */
- if (rxb && rxb->skb)
+ if (rxb->page)
iwl_tx_cmd_complete(priv, rxb);
else
IWL_WARN(priv, "Claim null rxb?\n");
}
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
+ /* Reuse the page if possible. For notification packets and
+ * SKBs that fail to Rx correctly, add them back into the
+ * rx_free list for reuse later. */
spin_lock_irqsave(&rxq->lock, flags);
- list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ if (rxb->page != NULL) {
+ rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page,
+ 0, PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ } else
+ list_add_tail(&rxb->list, &rxq->rx_used);
+
spin_unlock_irqrestore(&rxq->lock, flags);
+
i = (i + 1) & RX_QUEUE_MASK;
/* If there are a lot of unused frames,
* restock the Rx queue so ucode won't assert. */
if (fill_rx) {
count++;
if (count >= 8) {
- priv->rxq.read = i;
+ rxq->read = i;
iwl3945_rx_replenish_now(priv);
count = 0;
}
@@ -1466,7 +1467,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
}
/* Backtrack one entry */
- priv->rxq.read = i;
+ rxq->read = i;
if (fill_rx)
iwl3945_rx_replenish_now(priv);
else
@@ -1550,8 +1551,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
"%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
desc_lookup(desc), desc, time, blink1, blink2,
ilink1, ilink2, data1);
+ trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0,
+ 0, blink1, blink2, ilink1, ilink2);
}
-
}
#define EVENT_START_OFFSET (6 * sizeof(u32))
@@ -1591,10 +1593,12 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
if (mode == 0) {
/* data, ev */
IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
+ trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
+ trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
}
}
}
@@ -1684,6 +1688,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
}
#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
* atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after
@@ -1705,8 +1711,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1798,7 +1802,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
}
#endif
- spin_unlock_irqrestore(&priv->lock, flags);
}
static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
@@ -2478,7 +2481,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
iwl3945_reg_txpower_periodic(priv);
- iwl3945_led_register(priv);
+ iwl_leds_init(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
set_bit(STATUS_READY, &priv->status);
@@ -2516,7 +2519,6 @@ static void __iwl3945_down(struct iwl_priv *priv)
if (!exit_pending)
set_bit(STATUS_EXIT_PENDING, &priv->status);
- iwl3945_led_unregister(priv);
iwl_clear_stations_table(priv);
/* Unblock any waiting calls */
@@ -2562,11 +2564,6 @@ static void __iwl3945_down(struct iwl_priv *priv)
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;
- priv->cfg->ops->lib->apm_ops.reset(priv);
- spin_lock_irqsave(&priv->lock, flags);
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- spin_unlock_irqrestore(&priv->lock, flags);
-
iwl3945_hw_txq_ctx_stop(priv);
iwl3945_hw_rxq_stop(priv);
@@ -2575,10 +2572,8 @@ static void __iwl3945_down(struct iwl_priv *priv)
udelay(5);
- if (exit_pending)
- priv->cfg->ops->lib->apm_ops.stop(priv);
- else
- priv->cfg->ops->lib->apm_ops.reset(priv);
+ /* Stop the device, and put it in low power state */
+ priv->cfg->ops->lib->apm_ops.stop(priv);
exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@@ -2723,19 +2718,34 @@ static void iwl3945_bg_alive_start(struct work_struct *data)
mutex_unlock(&priv->mutex);
}
+/*
+ * 3945 cannot interrupt driver when hardware rf kill switch toggles;
+ * driver must poll CSR_GP_CNTRL_REG register for change. This register
+ * *is* readable even when device has been SW_RESET into low power mode
+ * (e.g. during RF KILL).
+ */
static void iwl3945_rfkill_poll(struct work_struct *data)
{
struct iwl_priv *priv =
container_of(data, struct iwl_priv, rfkill_poll.work);
+ bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status);
+ bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL)
+ & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
- if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
- else
- set_bit(STATUS_RF_KILL_HW, &priv->status);
+ if (new_rfkill != old_rfkill) {
+ if (new_rfkill)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
- wiphy_rfkill_set_hw_state(priv->hw->wiphy,
- test_bit(STATUS_RF_KILL_HW, &priv->status));
+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, new_rfkill);
+ IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ new_rfkill ? "disable radio" : "enable radio");
+ }
+
+ /* Keep this running, even if radio now enabled. This will be
+ * cancelled in mac_start() if system decides to start again */
queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
round_jiffies_relative(2 * HZ));
@@ -3151,6 +3161,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
* no need to poll the killswitch state anymore */
cancel_delayed_work(&priv->rfkill_poll);
+ iwl_led_start(priv);
+
priv->is_open = 1;
IWL_DEBUG_MAC80211(priv, "leave\n");
return 0;
@@ -3794,7 +3806,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
- priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ;
@@ -4053,6 +4064,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
&priv->bands[IEEE80211_BAND_2GHZ].channels[5]);
iwl3945_setup_deferred_work(priv);
iwl3945_setup_rx_handlers(priv);
+ iwl_power_initialize(priv);
/*********************************
* 8. Setup and Register mac80211
@@ -4123,6 +4135,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_down(priv);
}
+ /*
+ * Make sure device is reset to low power before unloading driver.
+ * This may be redundant with iwl_down(), but there are paths to
+ * run iwl_down() without calling apm_ops.stop(), and there are
+ * paths to avoid running iwl_down() at all before leaving driver.
+ * This (inexpensive) call *makes sure* device is reset.
+ */
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+
/* make sure we flush any pending irq or
* tasklet for the driver
*/
@@ -4225,18 +4246,19 @@ static void __exit iwl3945_exit(void)
MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX));
-module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444);
+module_param_named(antenna, iwl3945_mod_params.antenna, int, S_IRUGO);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
+module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n");
#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug, iwl_debug_level, uint, 0644);
+module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
-module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
+module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan,
+ int, S_IRUGO);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
module_exit(iwl3945_exit);
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index c25a04371ca..9606b3100fd 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -3,6 +3,7 @@ config IWM
depends on MMC && WLAN_80211 && EXPERIMENTAL
depends on CFG80211
select FW_LOADER
+ select IWMC3200TOP
help
The Intel Wireless Multicomm 3200 hardware is a combo
card with GPS, Bluetooth, WiMax and 802.11 radios. It
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index a56a2b0ac99..af72cc746f1 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -404,39 +404,21 @@ static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
struct ieee80211_channel *chan = params->channel;
- struct cfg80211_bss *bss;
if (!test_bit(IWM_STATUS_READY, &iwm->status))
return -EIO;
- /* UMAC doesn't support creating IBSS network with specified bssid.
- * This should be removed after we have join only mode supported. */
+ /* UMAC doesn't support creating or joining an IBSS network
+ * with specified bssid. */
if (params->bssid)
return -EOPNOTSUPP;
- bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
- params->ssid, params->ssid_len);
- if (!bss) {
- iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
- schedule_timeout_interruptible(2 * HZ);
- bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
- params->ssid, params->ssid_len);
- }
- /* IBSS join only mode is not supported by UMAC ATM */
- if (bss) {
- cfg80211_put_bss(bss);
- return -EOPNOTSUPP;
- }
-
iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
iwm->umac_profile->ibss.band = chan->band;
iwm->umac_profile->ibss.channel = iwm->channel;
iwm->umac_profile->ssid.ssid_len = params->ssid_len;
memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
- if (params->bssid)
- memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
-
return iwm_send_mlme_profile(iwm);
}
@@ -489,12 +471,12 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
return 0;
}
+ if (wpa_version & NL80211_WPA_VERSION_1)
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
+
if (wpa_version & NL80211_WPA_VERSION_2)
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
- if (wpa_version & NL80211_WPA_VERSION_1)
- iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
-
return 0;
}
@@ -645,6 +627,13 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
iwm->default_key = sme->key_idx;
}
+ /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */
+ if ((iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) &&
+ iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) {
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK;
+ }
+
ret = iwm_send_mlme_profile(iwm);
if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
@@ -681,9 +670,19 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
enum tx_power_setting type, int dbm)
{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ int ret;
+
switch (type) {
case TX_POWER_AUTOMATIC:
return 0;
+ case TX_POWER_FIXED:
+ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_TX_PWR_LIMIT_USR, dbm * 2);
+ if (ret < 0)
+ return ret;
+
+ return iwm_tx_power_trigger(iwm);
default:
return -EOPNOTSUPP;
}
@@ -695,7 +694,7 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
- *dbm = iwm->txpower;
+ *dbm = iwm->txpower >> 1;
return 0;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 23b52fa2605..cad511afd90 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -76,6 +76,11 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
int ret;
u8 oid = hdr->oid;
+ if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
+ IWM_ERR(iwm, "Interface is not ready yet");
+ return -EAGAIN;
+ }
+
umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
umac_cmd.resp = resp;
@@ -274,6 +279,17 @@ int iwm_send_calib_results(struct iwm_priv *iwm)
return ret;
}
+int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit)
+{
+ struct iwm_ct_kill_cfg_cmd cmd;
+
+ cmd.entry_threshold = entry;
+ cmd.exit_threshold = exit;
+
+ return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd,
+ sizeof(struct iwm_ct_kill_cfg_cmd), 0);
+}
+
int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp)
{
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
@@ -777,11 +793,24 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- (iwm->umac_profile_active == 0), 2 * HZ);
+ (iwm->umac_profile_active == 0), 5 * HZ);
return ret ? 0 : -EBUSY;
}
+int iwm_tx_power_trigger(struct iwm_priv *iwm)
+{
+ struct iwm_umac_pwr_trigger pwr_trigger;
+
+ pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER;
+ pwr_trigger.hdr.buf_size =
+ cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) -
+ sizeof(struct iwm_umac_wifi_if));
+
+
+ return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1);
+}
+
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
{
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index e24d5b63399..b36be2b23a3 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -102,7 +102,6 @@ enum {
CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN,
CFG_TLC_SUPPORTED_TX_HT_RATES,
CFG_TLC_SUPPORTED_TX_RATES,
- CFG_TLC_VALID_ANTENNA,
CFG_TLC_SPATIAL_STREAM_SUPPORTED,
CFG_TLC_RETRY_PER_RATE,
CFG_TLC_RETRY_PER_HT_RATE,
@@ -136,6 +135,10 @@ enum {
CFG_TLC_RENEW_ADDBA_DELAY,
CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD,
CFG_TLC_IS_STABLE_IN_HT,
+ CFG_TLC_SR_SIC_1ST_FAIL,
+ CFG_TLC_SR_SIC_1ST_PASS,
+ CFG_TLC_SR_SIC_TOTAL_FAIL,
+ CFG_TLC_SR_SIC_TOTAL_PASS,
CFG_RLC_CHAIN_CTRL,
CFG_TRK_TABLE_OP_MODE,
CFG_TRK_TABLE_RSSI_THRESHOLD,
@@ -147,6 +150,58 @@ enum {
CFG_MLME_DBG_NOTIF_BLOCK,
CFG_BT_OFF_BECONS_INTERVALS,
CFG_BT_FRAG_DURATION,
+ CFG_ACTIVE_CHAINS,
+ CFG_CALIB_CTRL,
+ CFG_CAPABILITY_SUPPORTED_HT_RATES,
+ CFG_HT_MAC_PARAM_INFO,
+ CFG_MIMO_PS_MODE,
+ CFG_HT_DEFAULT_CAPABILIES_INFO,
+ CFG_LED_SC_RESOLUTION_FACTOR,
+ CFG_PTAM_ENERGY_CCK_DET_DEFAULT,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT,
+ CFG_PTAM_ENERGY_CCK_DET_MIN_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL,
+ CFG_PTAM_ENERGY_CCK_DET_MAX_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL,
+ CFG_PTAM_ENERGY_CCK_DET_STEP_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL,
+ CFG_PTAM_LINK_SENS_FA_OFDM_MAX,
+ CFG_PTAM_LINK_SENS_FA_OFDM_MIN,
+ CFG_PTAM_LINK_SENS_FA_CCK_MAX,
+ CFG_PTAM_LINK_SENS_FA_CCK_MIN,
+ CFG_PTAM_LINK_SENS_NRG_DIFF,
+ CFG_PTAM_LINK_SENS_NRG_MARGIN,
+ CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA,
+ CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK,
+ CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD,
+ CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD,
+ CFG_AGG_MGG_ADDBA_BUF_SIZE,
+ CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT,
+ CFG_AGG_MGG_ADDBA_DEBUG_FLAGS,
+ CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD,
+ CFG_SCAN_PERIODIC_COEF_RSSI_HIGH,
+ CFG_11D_ENABLED,
+ CFG_11H_FEATURE_FLAGS,
/* <-- LAST --> */
CFG_TBL_FIX_LAST
@@ -155,7 +210,8 @@ enum {
/* variable size table */
enum {
CFG_NET_ADDR = 0,
- CFG_PROFILE,
+ CFG_LED_PATTERN_TABLE,
+
/* <-- LAST --> */
CFG_TBL_VAR_LAST
};
@@ -288,6 +344,9 @@ struct iwm_umac_cmd_scan_request {
/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */
#define UMAC_SEC_FLG_WSC_ON_POS 2
#define UMAC_SEC_FLG_WSC_ON_SEED 1
+#define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \
+ UMAC_SEC_FLG_WSC_ON_POS)
+
/* Legacy profile can use only WEP40 and WEP104 for encryption and
* OPEN or PSK for authentication */
@@ -382,6 +441,11 @@ struct iwm_umac_tx_key_id {
u8 reserved[3];
} __attribute__ ((packed));
+struct iwm_umac_pwr_trigger {
+ struct iwm_umac_wifi_if hdr;
+ __le32 reseved;
+} __attribute__ ((packed));
+
struct iwm_umac_cmd_stats_req {
__le32 flags;
} __attribute__ ((packed));
@@ -393,6 +457,7 @@ int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
int iwm_send_calib_results(struct iwm_priv *iwm);
int iwm_store_rxiq_calib_result(struct iwm_priv *iwm);
+int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit);
/* UMAC commands */
int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
@@ -407,6 +472,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
+int iwm_tx_power_trigger(struct iwm_priv *iwm);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index 6b0bcad758c..49067092d33 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -217,6 +217,13 @@ static int iwm_load_img(struct iwm_priv *iwm, const char *img_name)
IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date),
IWM_BUILD_DAY(build_date));
+ if (!strcmp(img_name, iwm->bus_ops->umac_name))
+ sprintf(iwm->umac_version, "%02X.%02X",
+ ver->major, ver->minor);
+
+ if (!strcmp(img_name, iwm->bus_ops->lmac_name))
+ sprintf(iwm->lmac_version, "%02X.%02X",
+ ver->major, ver->minor);
err_release_fw:
release_firmware(fw);
@@ -398,6 +405,8 @@ int iwm_load_fw(struct iwm_priv *iwm)
iwm_send_prio_table(iwm);
iwm_send_calib_results(iwm);
iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
+ iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry,
+ iwm->conf.ct_kill_exit);
return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 1b02a4e2a1a..a9bf6bc97be 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -65,6 +65,8 @@ struct iwm_conf {
u32 sdio_ior_timeout;
unsigned long calib_map;
unsigned long expected_calib_map;
+ u8 ct_kill_entry;
+ u8 ct_kill_exit;
bool reset_on_fatal_err;
bool auto_connect;
bool wimax_not_present;
@@ -276,12 +278,14 @@ struct iwm_priv {
struct iw_statistics wstats;
struct delayed_work stats_request;
struct delayed_work disconnect;
+ struct delayed_work ct_kill_delay;
struct iwm_debugfs dbg;
u8 *eeprom;
struct timer_list watchdog;
struct work_struct reset_worker;
+ struct work_struct auth_retry_worker;
struct mutex mutex;
u8 *req_ie;
@@ -290,6 +294,8 @@ struct iwm_priv {
int resp_ie_len;
struct iwm_fw_error_hdr *last_fw_err;
+ char umac_version[8];
+ char lmac_version[8];
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index 6c1a14c4480..a3a79b5e289 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -187,6 +187,14 @@ struct iwm_coex_prio_table_cmd {
COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
+/* CT kill config command */
+struct iwm_ct_kill_cfg_cmd {
+ u32 exit_threshold;
+ u32 reserved;
+ u32 entry_threshold;
+} __attribute__ ((packed));
+
+
/* LMAC OP CODES */
#define REPLY_PAD 0x0
#define REPLY_ALIVE 0x1
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index d668e475632..f93e9139b0f 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -63,6 +63,8 @@ static struct iwm_conf def_iwm_conf = {
BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) |
BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+ .ct_kill_entry = 110,
+ .ct_kill_exit = 110,
.reset_on_fatal_err = 1,
.auto_connect = 1,
.wimax_not_present = 0,
@@ -133,6 +135,17 @@ static void iwm_disconnect_work(struct work_struct *work)
cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
}
+static void iwm_ct_kill_work(struct work_struct *work)
+{
+ struct iwm_priv *iwm =
+ container_of(work, struct iwm_priv, ct_kill_delay.work);
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
+
+ IWM_INFO(iwm, "CT kill delay timeout\n");
+
+ wiphy_rfkill_set_hw_state(wiphy, false);
+}
+
static int __iwm_up(struct iwm_priv *iwm);
static int __iwm_down(struct iwm_priv *iwm);
@@ -194,6 +207,33 @@ static void iwm_reset_worker(struct work_struct *work)
mutex_unlock(&iwm->mutex);
}
+static void iwm_auth_retry_worker(struct work_struct *work)
+{
+ struct iwm_priv *iwm;
+ int i, ret;
+
+ iwm = container_of(work, struct iwm_priv, auth_retry_worker);
+ if (iwm->umac_profile_active) {
+ ret = iwm_invalidate_mlme_profile(iwm);
+ if (ret < 0)
+ return;
+ }
+
+ iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+
+ ret = iwm_send_mlme_profile(iwm);
+ if (ret < 0)
+ return;
+
+ for (i = 0; i < IWM_NUM_KEYS; i++)
+ if (iwm->keys[i].key_len)
+ iwm_set_key(iwm, 0, &iwm->keys[i]);
+
+ iwm_set_tx_key(iwm, iwm->default_key);
+}
+
+
+
static void iwm_watchdog(unsigned long data)
{
struct iwm_priv *iwm = (struct iwm_priv *)data;
@@ -225,7 +265,9 @@ int iwm_priv_init(struct iwm_priv *iwm)
iwm->scan_id = 1;
INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
+ INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work);
INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
+ INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker);
INIT_LIST_HEAD(&iwm->bss_list);
skb_queue_head_init(&iwm->rx_list);
@@ -586,6 +628,7 @@ static int __iwm_up(struct iwm_priv *iwm)
{
int ret;
struct iwm_notif *notif_reboot, *notif_ack = NULL;
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
ret = iwm_bus_enable(iwm);
if (ret) {
@@ -637,6 +680,8 @@ static int __iwm_up(struct iwm_priv *iwm)
IWM_ERR(iwm, "MAC reading failed\n");
goto err_disable;
}
+ memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr,
+ ETH_ALEN);
/* We can load the FWs */
ret = iwm_load_fw(iwm);
@@ -645,6 +690,9 @@ static int __iwm_up(struct iwm_priv *iwm)
goto err_disable;
}
+ snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s",
+ iwm->lmac_version, iwm->umac_version);
+
/* We configure the UMAC and enable the wifi module */
ret = iwm_send_umac_config(iwm,
cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) |
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index 35ec006c2d2..4f8dbdd7b91 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -152,6 +152,7 @@ void iwm_if_free(struct iwm_priv *iwm)
if (!iwm_to_ndev(iwm))
return;
+ cancel_delayed_work_sync(&iwm->ct_kill_delay);
free_netdev(iwm_to_ndev(iwm));
iwm_priv_deinit(iwm);
kfree(iwm->umac_profile);
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 40dbcbc1659..3ad95dc0dd8 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -422,7 +422,9 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node);
- IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+ IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n",
+ ticket->action == IWM_RX_TICKET_RELEASE ?
+ "RELEASE" : "DROP",
ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets);
@@ -499,6 +501,18 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
return 0;
}
+static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm)
+{
+ if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
+ iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
+ (iwm->umac_profile->sec.ucast_cipher ==
+ iwm->umac_profile->sec.mcast_cipher) &&
+ (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN))
+ return 1;
+
+ return 0;
+}
+
static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
@@ -564,11 +578,17 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
goto ibss;
if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
- cfg80211_connect_result(iwm_to_ndev(iwm),
- complete->bssid,
- NULL, 0, NULL, 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
+ if (!iwm_is_open_wep_profile(iwm)) {
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ } else {
+ /* Let's try shared WEP auth */
+ IWM_ERR(iwm, "Trying WEP shared auth\n");
+ schedule_work(&iwm->auth_retry_worker);
+ }
else
cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
GFP_KERNEL);
@@ -712,6 +732,19 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf,
return 0;
}
+static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf,
+ unsigned long buf_size,
+ struct iwm_wifi_cmd *cmd)
+{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
+
+ IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n");
+
+ wiphy_rfkill_set_hw_state(wiphy, true);
+
+ return 0;
+}
+
static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
@@ -898,6 +931,8 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED:
IWM_DBG_MLME(iwm, DBG, "Extended IE required\n");
break;
+ case WIFI_IF_NTFY_RADIO_PREEMPTION:
+ return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED:
return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED:
@@ -1055,8 +1090,14 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
- struct iwm_umac_wifi_if *hdr =
- (struct iwm_umac_wifi_if *)cmd->buf.payload;
+ struct iwm_umac_wifi_if *hdr;
+
+ if (cmd == NULL) {
+ IWM_ERR(iwm, "Couldn't find expected wifi command\n");
+ return -EINVAL;
+ }
+
+ hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload;
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
"oid is 0x%x\n", hdr->oid);
@@ -1078,6 +1119,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
return 0;
}
+#define CT_KILL_DELAY (30 * HZ)
static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
@@ -1090,7 +1132,20 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
- wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
+ if (flags & IWM_CARD_STATE_CTKILL_DISABLED) {
+ /*
+ * We got a CTKILL event: We bring the interface down in
+ * oder to cool the device down, and try to bring it up
+ * 30 seconds later. If it's still too hot, we'll go through
+ * this code path again.
+ */
+ cancel_delayed_work_sync(&iwm->ct_kill_delay);
+ schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY);
+ }
+
+ wiphy_rfkill_set_hw_state(wiphy, flags &
+ (IWM_CARD_STATE_HW_DISABLED |
+ IWM_CARD_STATE_CTKILL_DISABLED));
return 0;
}
@@ -1281,6 +1336,14 @@ int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size)
switch (le32_to_cpu(hdr->cmd)) {
case UMAC_REBOOT_BARKER:
+ if (test_bit(IWM_STATUS_READY, &iwm->status)) {
+ IWM_ERR(iwm, "Unexpected BARKER\n");
+
+ schedule_work(&iwm->reset_worker);
+
+ return 0;
+ }
+
return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION,
IWM_SRC_UDMA, buf, buf_size);
case UMAC_ACK_BARKER:
@@ -1443,7 +1506,8 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
}
break;
case IWM_RX_TICKET_DROP:
- IWM_DBG_RX(iwm, DBG, "DROP packet\n");
+ IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n",
+ le16_to_cpu(ticket_node->ticket->flags));
kfree_skb(packet->skb);
break;
default:
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 8b1de84003c..cf86294f719 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -224,8 +224,6 @@ static int if_sdio_disable(struct iwm_priv *iwm)
struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
int ret;
- iwm_reset(iwm);
-
sdio_claim_host(hw->func);
sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
if (ret < 0)
@@ -237,6 +235,8 @@ static int if_sdio_disable(struct iwm_priv *iwm)
iwm_sdio_rx_free(hw);
+ iwm_reset(iwm);
+
IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n");
return 0;
@@ -493,8 +493,10 @@ static void iwm_sdio_remove(struct sdio_func *func)
}
static const struct sdio_device_id iwm_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
- SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) },
+ /* Global/AGN SKU */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) },
+ /* BGN SKU */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index c5a14ae3160..be903543bb4 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -687,6 +687,9 @@ struct iwm_umac_notif_rx_ticket {
/* Tx/Rx rates window (number of max of last update window per second) */
#define UMAC_NTF_RATE_SAMPLE_NR 4
+/* Max numbers of bits required to go through all antennae in bitmasks */
+#define UMAC_PHY_NUM_CHAINS 3
+
#define IWM_UMAC_MGMT_TID 8
#define IWM_UMAC_TID_NR 8
@@ -697,9 +700,11 @@ struct iwm_umac_notif_stats {
__le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */
__le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
__le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
+ __le32 chain_energy[UMAC_PHY_NUM_CHAINS];
s32 rssi_dbm;
s32 noise_dbm;
__le32 supp_rates;
+ __le32 supp_ht_rates;
__le32 missed_beacons;
__le32 rx_beacons;
__le32 rx_dir_pkts;
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
deleted file mode 100644
index 5c6968101f0..00000000000
--- a/drivers/net/wireless/libertas/11d.c
+++ /dev/null
@@ -1,696 +0,0 @@
-/**
- * This file contains functions for 802.11D.
- */
-#include <linux/ctype.h>
-#include <linux/kernel.h>
-#include <linux/wireless.h>
-
-#include "host.h"
-#include "decl.h"
-#include "11d.h"
-#include "dev.h"
-#include "wext.h"
-
-#define TX_PWR_DEFAULT 10
-
-static struct region_code_mapping region_code_mapping[] = {
- {"US ", 0x10}, /* US FCC */
- {"CA ", 0x10}, /* IC Canada */
- {"SG ", 0x10}, /* Singapore */
- {"EU ", 0x30}, /* ETSI */
- {"AU ", 0x30}, /* Australia */
- {"KR ", 0x30}, /* Republic Of Korea */
- {"ES ", 0x31}, /* Spain */
- {"FR ", 0x32}, /* France */
- {"JP ", 0x40}, /* Japan */
-};
-
-/* Following 2 structure defines the supported channels */
-static struct chan_freq_power channel_freq_power_UN_BG[] = {
- {1, 2412, TX_PWR_DEFAULT},
- {2, 2417, TX_PWR_DEFAULT},
- {3, 2422, TX_PWR_DEFAULT},
- {4, 2427, TX_PWR_DEFAULT},
- {5, 2432, TX_PWR_DEFAULT},
- {6, 2437, TX_PWR_DEFAULT},
- {7, 2442, TX_PWR_DEFAULT},
- {8, 2447, TX_PWR_DEFAULT},
- {9, 2452, TX_PWR_DEFAULT},
- {10, 2457, TX_PWR_DEFAULT},
- {11, 2462, TX_PWR_DEFAULT},
- {12, 2467, TX_PWR_DEFAULT},
- {13, 2472, TX_PWR_DEFAULT},
- {14, 2484, TX_PWR_DEFAULT}
-};
-
-static u8 lbs_region_2_code(u8 *region)
-{
- u8 i;
-
- for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
- region[i] = toupper(region[i]);
-
- for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
- if (!memcmp(region, region_code_mapping[i].region,
- COUNTRY_CODE_LEN))
- return (region_code_mapping[i].code);
- }
-
- /* default is US */
- return (region_code_mapping[0].code);
-}
-
-static u8 *lbs_code_2_region(u8 code)
-{
- u8 i;
-
- for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
- if (region_code_mapping[i].code == code)
- return (region_code_mapping[i].region);
- }
- /* default is US */
- return (region_code_mapping[0].region);
-}
-
-/**
- * @brief This function finds the nrchan-th chan after the firstchan
- * @param band band
- * @param firstchan first channel number
- * @param nrchan number of channels
- * @return the nrchan-th chan number
-*/
-static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan)
-/*find the nrchan-th chan after the firstchan*/
-{
- u8 i;
- struct chan_freq_power *cfp;
- u8 cfp_no;
-
- cfp = channel_freq_power_UN_BG;
- cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
-
- for (i = 0; i < cfp_no; i++) {
- if ((cfp + i)->channel == firstchan) {
- lbs_deb_11d("firstchan found\n");
- break;
- }
- }
-
- if (i < cfp_no) {
- /*if beyond the boundary */
- if (i + nrchan < cfp_no) {
- *chan = (cfp + i + nrchan)->channel;
- return 1;
- }
- }
-
- return 0;
-}
-
-/**
- * @brief This function Checks if chan txpwr is learned from AP/IBSS
- * @param chan chan number
- * @param parsed_region_chan pointer to parsed_region_chan_11d
- * @return TRUE; FALSE
-*/
-static u8 lbs_channel_known_11d(u8 chan,
- struct parsed_region_chan_11d * parsed_region_chan)
-{
- struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
- u8 nr_chan = parsed_region_chan->nr_chan;
- u8 i = 0;
-
- lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
- sizeof(struct chan_power_11d) * nr_chan);
-
- for (i = 0; i < nr_chan; i++) {
- if (chan == chanpwr[i].chan) {
- lbs_deb_11d("found chan %d\n", chan);
- return 1;
- }
- }
-
- lbs_deb_11d("chan %d not found\n", chan);
- return 0;
-}
-
-u32 lbs_chan_2_freq(u8 chan)
-{
- struct chan_freq_power *cf;
- u16 i;
- u32 freq = 0;
-
- cf = channel_freq_power_UN_BG;
-
- for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
- if (chan == cf[i].channel)
- freq = cf[i].freq;
- }
-
- return freq;
-}
-
-static int generate_domain_info_11d(struct parsed_region_chan_11d
- *parsed_region_chan,
- struct lbs_802_11d_domain_reg *domaininfo)
-{
- u8 nr_subband = 0;
-
- u8 nr_chan = parsed_region_chan->nr_chan;
- u8 nr_parsedchan = 0;
-
- u8 firstchan = 0, nextchan = 0, maxpwr = 0;
-
- u8 i, flag = 0;
-
- memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
- COUNTRY_CODE_LEN);
-
- lbs_deb_11d("nrchan %d\n", nr_chan);
- lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
- sizeof(struct parsed_region_chan_11d));
-
- for (i = 0; i < nr_chan; i++) {
- if (!flag) {
- flag = 1;
- nextchan = firstchan =
- parsed_region_chan->chanpwr[i].chan;
- maxpwr = parsed_region_chan->chanpwr[i].pwr;
- nr_parsedchan = 1;
- continue;
- }
-
- if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
- parsed_region_chan->chanpwr[i].pwr == maxpwr) {
- nextchan++;
- nr_parsedchan++;
- } else {
- domaininfo->subband[nr_subband].firstchan = firstchan;
- domaininfo->subband[nr_subband].nrchan =
- nr_parsedchan;
- domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
- nr_subband++;
- nextchan = firstchan =
- parsed_region_chan->chanpwr[i].chan;
- maxpwr = parsed_region_chan->chanpwr[i].pwr;
- }
- }
-
- if (flag) {
- domaininfo->subband[nr_subband].firstchan = firstchan;
- domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
- domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
- nr_subband++;
- }
- domaininfo->nr_subband = nr_subband;
-
- lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
- lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
- COUNTRY_CODE_LEN + 1 +
- sizeof(struct ieee_subbandset) * nr_subband);
- return 0;
-}
-
-/**
- * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
- * @param region_chan pointer to struct region_channel
- * @param *parsed_region_chan pointer to parsed_region_chan_11d
- * @return N/A
-*/
-static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
- struct parsed_region_chan_11d *
- parsed_region_chan)
-{
- u8 i;
- struct chan_freq_power *cfp;
-
- if (region_chan == NULL) {
- lbs_deb_11d("region_chan is NULL\n");
- return;
- }
-
- cfp = region_chan->CFP;
- if (cfp == NULL) {
- lbs_deb_11d("cfp is NULL \n");
- return;
- }
-
- parsed_region_chan->band = region_chan->band;
- parsed_region_chan->region = region_chan->region;
- memcpy(parsed_region_chan->countrycode,
- lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
-
- lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
- parsed_region_chan->band);
-
- for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
- parsed_region_chan->chanpwr[i].chan = cfp->channel;
- parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
- lbs_deb_11d("chan %d, pwr %d\n",
- parsed_region_chan->chanpwr[i].chan,
- parsed_region_chan->chanpwr[i].pwr);
- }
- parsed_region_chan->nr_chan = region_chan->nrcfp;
-
- lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
-
- return;
-}
-
-/**
- * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
- * @param region region ID
- * @param band band
- * @param chan chan
- * @return TRUE;FALSE
-*/
-static u8 lbs_region_chan_supported_11d(u8 region, u8 chan)
-{
- struct chan_freq_power *cfp;
- int cfp_no;
- u8 idx;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- cfp = lbs_get_region_cfp_table(region, &cfp_no);
- if (cfp == NULL)
- return 0;
-
- for (idx = 0; idx < cfp_no; idx++) {
- if (chan == (cfp + idx)->channel) {
- /* If Mrvl Chip Supported? */
- if ((cfp + idx)->unsupported) {
- ret = 0;
- } else {
- ret = 1;
- }
- goto done;
- }
- }
-
- /*chan is not in the region table */
-
-done:
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief This function checks if chan txpwr is learned from AP/IBSS
- * @param chan chan number
- * @param parsed_region_chan pointer to parsed_region_chan_11d
- * @return 0
-*/
-static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
- u8 band,
- struct parsed_region_chan_11d *parsed_region_chan)
-{
- u8 nr_subband, nrchan;
- u8 lastchan, firstchan;
- u8 region;
- u8 curchan = 0;
-
- u8 idx = 0; /*chan index in parsed_region_chan */
-
- u8 j, i;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- /*validation Rules:
- 1. valid region Code
- 2. First Chan increment
- 3. channel range no overlap
- 4. channel is valid?
- 5. channel is supported by region?
- 6. Others
- */
-
- lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
-
- if ((*(countryinfo->countrycode)) == 0
- || (countryinfo->header.len <= COUNTRY_CODE_LEN)) {
- /* No region Info or Wrong region info: treat as No 11D info */
- goto done;
- }
-
- /*Step1: check region_code */
- parsed_region_chan->region = region =
- lbs_region_2_code(countryinfo->countrycode);
-
- lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
- lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
- COUNTRY_CODE_LEN);
-
- parsed_region_chan->band = band;
-
- memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
- COUNTRY_CODE_LEN);
-
- nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
- sizeof(struct ieee_subbandset);
-
- for (j = 0, lastchan = 0; j < nr_subband; j++) {
-
- if (countryinfo->subband[j].firstchan <= lastchan) {
- /*Step2&3. Check First Chan Num increment and no overlap */
- lbs_deb_11d("chan %d>%d, overlap\n",
- countryinfo->subband[j].firstchan, lastchan);
- continue;
- }
-
- firstchan = countryinfo->subband[j].firstchan;
- nrchan = countryinfo->subband[j].nrchan;
-
- for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
- /*step4: channel is supported? */
-
- if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
- /* Chan is not found in UN table */
- lbs_deb_11d("chan is not supported: %d \n", i);
- break;
- }
-
- lastchan = curchan;
-
- if (lbs_region_chan_supported_11d(region, curchan)) {
- /*step5: Check if curchan is supported by mrvl in region */
- parsed_region_chan->chanpwr[idx].chan = curchan;
- parsed_region_chan->chanpwr[idx].pwr =
- countryinfo->subband[j].maxtxpwr;
- idx++;
- } else {
- /*not supported and ignore the chan */
- lbs_deb_11d(
- "i %d, chan %d unsupported in region %x, band %d\n",
- i, curchan, region, band);
- }
- }
-
- /*Step6: Add other checking if any */
-
- }
-
- parsed_region_chan->nr_chan = idx;
-
- lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
- lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
- 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
-
-done:
- lbs_deb_enter(LBS_DEB_11D);
- return 0;
-}
-
-/**
- * @brief This function calculates the scan type for channels
- * @param chan chan number
- * @param parsed_region_chan pointer to parsed_region_chan_11d
- * @return PASSIVE if chan is unknown; ACTIVE if chan is known
-*/
-u8 lbs_get_scan_type_11d(u8 chan,
- struct parsed_region_chan_11d * parsed_region_chan)
-{
- u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- if (lbs_channel_known_11d(chan, parsed_region_chan)) {
- lbs_deb_11d("found, do active scan\n");
- scan_type = CMD_SCAN_TYPE_ACTIVE;
- } else {
- lbs_deb_11d("not found, do passive scan\n");
- }
-
- lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
- return scan_type;
-
-}
-
-void lbs_init_11d(struct lbs_private *priv)
-{
- priv->enable11d = 0;
- memset(&(priv->parsed_region_chan), 0,
- sizeof(struct parsed_region_chan_11d));
- return;
-}
-
-/**
- * @brief This function sets DOMAIN INFO to FW
- * @param priv pointer to struct lbs_private
- * @return 0; -1
-*/
-static int set_domain_info_11d(struct lbs_private *priv)
-{
- int ret;
-
- if (!priv->enable11d) {
- lbs_deb_11d("dnld domain Info with 11d disabled\n");
- return 0;
- }
-
- ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
- CMD_ACT_SET,
- CMD_OPTION_WAITFORRSP, 0, NULL);
- if (ret)
- lbs_deb_11d("fail to dnld domain info\n");
-
- return ret;
-}
-
-/**
- * @brief This function setups scan channels
- * @param priv pointer to struct lbs_private
- * @param band band
- * @return 0
-*/
-int lbs_set_universaltable(struct lbs_private *priv, u8 band)
-{
- u16 size = sizeof(struct chan_freq_power);
- u16 i = 0;
-
- memset(priv->universal_channel, 0,
- sizeof(priv->universal_channel));
-
- priv->universal_channel[i].nrcfp =
- sizeof(channel_freq_power_UN_BG) / size;
- lbs_deb_11d("BG-band nrcfp %d\n",
- priv->universal_channel[i].nrcfp);
-
- priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
- priv->universal_channel[i].valid = 1;
- priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
- priv->universal_channel[i].band = band;
- i++;
-
- return 0;
-}
-
-/**
- * @brief This function implements command CMD_802_11D_DOMAIN_INFO
- * @param priv pointer to struct lbs_private
- * @param cmd pointer to cmd buffer
- * @param cmdno cmd ID
- * @param cmdOption cmd action
- * @return 0
-*/
-int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
- struct cmd_ds_command *cmd, u16 cmdno,
- u16 cmdoption)
-{
- struct cmd_ds_802_11d_domain_info *pdomaininfo =
- &cmd->params.domaininfo;
- struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
- u8 nr_subband = priv->domainreg.nr_subband;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- lbs_deb_11d("nr_subband=%x\n", nr_subband);
-
- cmd->command = cpu_to_le16(cmdno);
- pdomaininfo->action = cpu_to_le16(cmdoption);
- if (cmdoption == CMD_ACT_GET) {
- cmd->size =
- cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
- lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
- le16_to_cpu(cmd->size));
- goto done;
- }
-
- domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
- memcpy(domain->countrycode, priv->domainreg.countrycode,
- sizeof(domain->countrycode));
-
- domain->header.len =
- cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
- sizeof(domain->countrycode));
-
- if (nr_subband) {
- memcpy(domain->subband, priv->domainreg.subband,
- nr_subband * sizeof(struct ieee_subbandset));
-
- cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
- le16_to_cpu(domain->header.len) +
- sizeof(struct mrvl_ie_header) +
- S_DS_GEN);
- } else {
- cmd->size =
- cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
- }
-
- lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
-
-done:
- lbs_deb_enter(LBS_DEB_11D);
- return 0;
-}
-
-/**
- * @brief This function parses countryinfo from AP and download country info to FW
- * @param priv pointer to struct lbs_private
- * @param resp pointer to command response buffer
- * @return 0; -1
- */
-int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
- struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
- u16 action = le16_to_cpu(domaininfo->action);
- s16 ret = 0;
- u8 nr_subband = 0;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
- (int)le16_to_cpu(resp->size));
-
- nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
- sizeof(struct ieee_subbandset);
-
- lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
-
- if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
- lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
- return -1;
- }
-
- switch (action) {
- case CMD_ACT_SET: /*Proc Set action */
- break;
-
- case CMD_ACT_GET:
- break;
- default:
- lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
- ret = -1;
- break;
- }
-
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief This function parses countryinfo from AP and download country info to FW
- * @param priv pointer to struct lbs_private
- * @return 0; -1
- */
-int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
- struct bss_descriptor * bss)
-{
- int ret;
-
- lbs_deb_enter(LBS_DEB_11D);
- if (priv->enable11d) {
- memset(&priv->parsed_region_chan, 0,
- sizeof(struct parsed_region_chan_11d));
- ret = parse_domain_info_11d(&bss->countryinfo, 0,
- &priv->parsed_region_chan);
-
- if (ret == -1) {
- lbs_deb_11d("error parsing domain_info from AP\n");
- goto done;
- }
-
- memset(&priv->domainreg, 0,
- sizeof(struct lbs_802_11d_domain_reg));
- generate_domain_info_11d(&priv->parsed_region_chan,
- &priv->domainreg);
-
- ret = set_domain_info_11d(priv);
-
- if (ret) {
- lbs_deb_11d("error setting domain info\n");
- goto done;
- }
- }
- ret = 0;
-
-done:
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief This function generates 11D info from user specified regioncode and download to FW
- * @param priv pointer to struct lbs_private
- * @return 0; -1
- */
-int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
-{
- int ret;
- struct region_channel *region_chan;
- u8 j;
-
- lbs_deb_enter(LBS_DEB_11D);
- lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
-
- if (priv->enable11d) {
- /* update parsed_region_chan_11; dnld domaininf to FW */
-
- for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
- region_chan = &priv->region_channel[j];
-
- lbs_deb_11d("%d region_chan->band %d\n", j,
- region_chan->band);
-
- if (!region_chan || !region_chan->valid
- || !region_chan->CFP)
- continue;
- if (region_chan->band != priv->curbssparams.band)
- continue;
- break;
- }
-
- if (j >= ARRAY_SIZE(priv->region_channel)) {
- lbs_deb_11d("region_chan not found, band %d\n",
- priv->curbssparams.band);
- ret = -1;
- goto done;
- }
-
- memset(&priv->parsed_region_chan, 0,
- sizeof(struct parsed_region_chan_11d));
- lbs_generate_parsed_region_chan_11d(region_chan,
- &priv->
- parsed_region_chan);
-
- memset(&priv->domainreg, 0,
- sizeof(struct lbs_802_11d_domain_reg));
- generate_domain_info_11d(&priv->parsed_region_chan,
- &priv->domainreg);
-
- ret = set_domain_info_11d(priv);
-
- if (ret) {
- lbs_deb_11d("error setting domain info\n");
- goto done;
- }
-
- }
- ret = 0;
-
-done:
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
deleted file mode 100644
index fb75d3e321a..00000000000
--- a/drivers/net/wireless/libertas/11d.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * This header file contains data structures and
- * function declarations of 802.11d
- */
-#ifndef _LBS_11D_
-#define _LBS_11D_
-
-#include "types.h"
-#include "defs.h"
-
-#define UNIVERSAL_REGION_CODE 0xff
-
-/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
- */
-#define MRVDRV_MAX_SUBBAND_802_11D 83
-
-#define COUNTRY_CODE_LEN 3
-#define MAX_NO_OF_CHAN 40
-
-struct cmd_ds_command;
-
-/** Data structure for Country IE*/
-struct ieee_subbandset {
- u8 firstchan;
- u8 nrchan;
- u8 maxtxpwr;
-} __attribute__ ((packed));
-
-struct ieee_ie_country_info_set {
- struct ieee_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[1];
-};
-
-struct ieee_ie_country_info_full_set {
- struct ieee_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
-} __attribute__ ((packed));
-
-struct mrvl_ie_domain_param_set {
- struct mrvl_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[1];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11d_domain_info {
- __le16 action;
- struct mrvl_ie_domain_param_set domain;
-} __attribute__ ((packed));
-
-/** domain regulatory information */
-struct lbs_802_11d_domain_reg {
- /** country Code*/
- u8 countrycode[COUNTRY_CODE_LEN];
- /** No. of subband*/
- u8 nr_subband;
- struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
-};
-
-struct chan_power_11d {
- u8 chan;
- u8 pwr;
-} __attribute__ ((packed));
-
-struct parsed_region_chan_11d {
- u8 band;
- u8 region;
- s8 countrycode[COUNTRY_CODE_LEN];
- struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
- u8 nr_chan;
-} __attribute__ ((packed));
-
-struct region_code_mapping {
- u8 region[COUNTRY_CODE_LEN];
- u8 code;
-};
-
-struct lbs_private;
-
-u8 lbs_get_scan_type_11d(u8 chan,
- struct parsed_region_chan_11d *parsed_region_chan);
-
-u32 lbs_chan_2_freq(u8 chan);
-
-void lbs_init_11d(struct lbs_private *priv);
-
-int lbs_set_universaltable(struct lbs_private *priv, u8 band);
-
-int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
- struct cmd_ds_command *cmd, u16 cmdno,
- u16 cmdOption);
-
-int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
-
-struct bss_descriptor;
-int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
- struct bss_descriptor * bss);
-
-int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv);
-
-#endif
diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig
new file mode 100644
index 00000000000..8f8d75b61ea
--- /dev/null
+++ b/drivers/net/wireless/libertas/Kconfig
@@ -0,0 +1,39 @@
+config LIBERTAS
+ tristate "Marvell 8xxx Libertas WLAN driver support"
+ depends on WLAN_80211 && CFG80211
+ select WIRELESS_EXT
+ select WEXT_SPY
+ select LIB80211
+ select FW_LOADER
+ ---help---
+ A library for Marvell Libertas 8xxx devices.
+
+config LIBERTAS_USB
+ tristate "Marvell Libertas 8388 USB 802.11b/g cards"
+ depends on LIBERTAS && USB
+ ---help---
+ A driver for Marvell Libertas 8388 USB devices.
+
+config LIBERTAS_CS
+ tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
+ depends on LIBERTAS && PCMCIA
+ ---help---
+ A driver for Marvell Libertas 8385 CompactFlash devices.
+
+config LIBERTAS_SDIO
+ tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
+ depends on LIBERTAS && MMC
+ ---help---
+ A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
+
+config LIBERTAS_SPI
+ tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
+ depends on LIBERTAS && SPI
+ ---help---
+ A driver for Marvell Libertas 8686 SPI devices.
+
+config LIBERTAS_DEBUG
+ bool "Enable full debugging output in the Libertas module."
+ depends on LIBERTAS
+ ---help---
+ Debugging support.
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 0b691858450..fa37039e0ea 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,5 +1,15 @@
-libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
- debugfs.o persistcfg.o ethtool.o assoc.o
+libertas-y += assoc.o
+libertas-y += cfg.o
+libertas-y += cmd.o
+libertas-y += cmdresp.o
+libertas-y += debugfs.o
+libertas-y += ethtool.o
+libertas-y += main.o
+libertas-y += persistcfg.o
+libertas-y += rx.o
+libertas-y += scan.o
+libertas-y += tx.o
+libertas-y += wext.o
usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index ab6a2d518af..2726c044430 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -1,5 +1,5 @@
================================================================================
- README for USB8388
+ README for Libertas
(c) Copyright © 2003-2006, Marvell International Ltd.
All Rights Reserved
@@ -226,4 +226,28 @@ setuserscan
All entries in the scan table (not just the new scan data when keep=1)
will be displayed upon completion by use of the getscantable ioctl.
+========================
+IWCONFIG COMMANDS
+========================
+power period
+
+ This command is used to configure the station in deep sleep mode /
+ auto deep sleep mode.
+
+ The timer is implemented to monitor the activities (command, event,
+ etc.). When an activity is detected station will exit from deep
+ sleep mode automatically and restart the timer. At timer expiry
+ (no activity for defined time period) the deep sleep mode is entered
+ automatically.
+
+ Note: this command is for SDIO interface only.
+
+ Usage:
+ To enable deep sleep mode do:
+ iwconfig wlan0 power period 0
+ To enable auto deep sleep mode with idle time period 5 seconds do:
+ iwconfig wlan0 power period 5
+ To disable deep sleep/auto deep sleep mode do:
+ iwconfig wlan0 power period -1
+
==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index dd8732611ba..751067369ba 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -23,6 +23,13 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
*/
#define CAPINFO_MASK (~(0xda00))
+/**
+ * 802.11b/g supported bitrates (in 500Kb/s units)
+ */
+u8 lbs_bg_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0x00, 0x00 };
+
/**
* @brief This function finds common rates between rates and card rates.
@@ -147,6 +154,397 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
}
+int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc)
+{
+ struct cmd_ds_802_11_set_wep cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ cmd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == CMD_ACT_ADD) {
+ int i;
+
+ /* default tx key index */
+ cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
+ CMD_WEP_KEY_INDEX_MASK);
+
+ /* Copy key types and material to host command structure */
+ for (i = 0; i < 4; i++) {
+ struct enc_key *pkey = &assoc->wep_keys[i];
+
+ switch (pkey->len) {
+ case KEY_LEN_WEP_40:
+ cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+ memmove(cmd.keymaterial[i], pkey->key, pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
+ break;
+ case KEY_LEN_WEP_104:
+ cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+ memmove(cmd.keymaterial[i], pkey->key, pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
+ break;
+ case 0:
+ break;
+ default:
+ lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
+ i, pkey->len);
+ ret = -1;
+ goto done;
+ break;
+ }
+ }
+ } else if (cmd_action == CMD_ACT_REMOVE) {
+ /* ACT_REMOVE clears _all_ WEP keys */
+
+ /* default tx key index */
+ cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
+ CMD_WEP_KEY_INDEX_MASK);
+ lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+done:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
+ uint16_t *enable)
+{
+ struct cmd_ds_802_11_enable_rsn cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == CMD_ACT_GET)
+ cmd.enable = 0;
+ else {
+ if (*enable)
+ cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
+ else
+ cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
+ lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+ if (!ret && cmd_action == CMD_ACT_GET)
+ *enable = le16_to_cpu(cmd.enable);
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
+ struct enc_key *key)
+{
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (key->flags & KEY_INFO_WPA_ENABLED)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
+ if (key->flags & KEY_INFO_WPA_UNICAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+ if (key->flags & KEY_INFO_WPA_MCAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+
+ keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ keyparam->keytypeid = cpu_to_le16(key->type);
+ keyparam->keylen = cpu_to_le16(key->len);
+ memcpy(keyparam->key, key->key, key->len);
+
+ /* Length field doesn't include the {type,length} header */
+ keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc)
+{
+ struct cmd_ds_802_11_key_material cmd;
+ int ret = 0;
+ int index = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ if (cmd_action == CMD_ACT_GET) {
+ cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
+ } else {
+ memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
+
+ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_unicast_key);
+ index++;
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_mcast_key);
+ index++;
+ }
+
+ /* The common header and as many keys as we included */
+ cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
+ keyParamSet[index]));
+ }
+ ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+ /* Copy the returned key to driver private data */
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ void *buf_ptr = cmd.keyParamSet;
+ void *resp_end = &(&cmd)[1];
+
+ while (buf_ptr < resp_end) {
+ struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
+ struct enc_key *key;
+ uint16_t param_set_len = le16_to_cpu(keyparam->length);
+ uint16_t key_len = le16_to_cpu(keyparam->keylen);
+ uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
+ uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
+ void *end;
+
+ end = (void *)keyparam + sizeof(keyparam->type)
+ + sizeof(keyparam->length) + param_set_len;
+
+ /* Make sure we don't access past the end of the IEs */
+ if (end > resp_end)
+ break;
+
+ if (key_flags & KEY_INFO_WPA_UNICAST)
+ key = &priv->wpa_unicast_key;
+ else if (key_flags & KEY_INFO_WPA_MCAST)
+ key = &priv->wpa_mcast_key;
+ else
+ break;
+
+ /* Copy returned key into driver */
+ memset(key, 0, sizeof(struct enc_key));
+ if (key_len > sizeof(key->key))
+ break;
+ key->type = key_type;
+ key->flags = key_flags;
+ key->len = key_len;
+ memcpy(key->key, keyparam->key, key->len);
+
+ buf_ptr = end + 1;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
+{
+/* Bit Rate
+* 15:13 Reserved
+* 12 54 Mbps
+* 11 48 Mbps
+* 10 36 Mbps
+* 9 24 Mbps
+* 8 18 Mbps
+* 7 12 Mbps
+* 6 9 Mbps
+* 5 6 Mbps
+* 4 Reserved
+* 3 11 Mbps
+* 2 5.5 Mbps
+* 1 2 Mbps
+* 0 1 Mbps
+**/
+
+ uint16_t ratemask;
+ int i = lbs_data_rate_to_fw_index(rate);
+ if (lower_rates_ok)
+ ratemask = (0x1fef >> (12 - i));
+ else
+ ratemask = (1 << i);
+ return cpu_to_le16(ratemask);
+}
+
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action)
+{
+ struct cmd_ds_802_11_rate_adapt_rateset cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (!priv->cur_rate && !priv->enablehwauto)
+ return -EINVAL;
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
+ cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+ priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Set the data rate
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param rate The desired data rate, or 0 to clear a locked rate
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
+{
+ struct cmd_ds_802_11_data_rate cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ if (rate > 0) {
+ cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
+ cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
+ if (cmd.rates[0] == 0) {
+ lbs_deb_cmd("DATA_RATE: invalid requested rate of"
+ " 0x%02X\n", rate);
+ ret = 0;
+ goto out;
+ }
+ lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
+ } else {
+ cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
+ lbs_deb_cmd("DATA_RATE: setting auto\n");
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
+ if (ret)
+ goto out;
+
+ lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
+
+ /* FIXME: get actual rates FW can do if this command actually returns
+ * all data rates supported.
+ */
+ priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
+ lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+
+int lbs_cmd_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+{
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RSSI);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
+ sizeof(struct cmd_header));
+ cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
+
+ /* reset Beacon SNR/NF/RSSI values */
+ priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+ priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
+ priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+int lbs_ret_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ /* store the non average value */
+ priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
+ priv->NF[TYPE_BEACON][TYPE_NOAVG] =
+ get_unaligned_le16(&rssirsp->noisefloor);
+
+ priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
+ priv->NF[TYPE_BEACON][TYPE_AVG] =
+ get_unaligned_le16(&rssirsp->avgnoisefloor);
+
+ priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+ CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
+ priv->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+ priv->RSSI[TYPE_BEACON][TYPE_AVG] =
+ CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+ priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+ lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
+ priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
+ priv->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+
+int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_beacon_control
+ *bcn_ctrl = &cmd->params.bcn_ctrl;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
+ + sizeof(struct cmd_header));
+ cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
+
+ bcn_ctrl->action = cpu_to_le16(cmd_action);
+ bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
+ bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_beacon_control *bcn_ctrl =
+ &resp->params.bcn_ctrl;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (bcn_ctrl->action == CMD_ACT_GET) {
+ priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
+ priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
+ }
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ return 0;
+}
+
+
+
static int lbs_assoc_post(struct lbs_private *priv,
struct cmd_ds_802_11_associate_response *resp)
{
@@ -226,7 +624,7 @@ static int lbs_assoc_post(struct lbs_private *priv,
priv->connect_status = LBS_CONNECTED;
/* Update current SSID and BSSID */
- memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len;
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
@@ -369,12 +767,7 @@ static int lbs_associate(struct lbs_private *priv,
(u16)(pos - (u8 *) &cmd.iebuf));
/* update curbssparams */
- priv->curbssparams.channel = bss->phy.ds.channel;
-
- if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
- ret = -1;
- goto done;
- }
+ priv->channel = bss->phy.ds.channel;
ret = lbs_cmd_with_response(priv, command, &cmd);
if (ret == 0) {
@@ -472,7 +865,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
/* Set the new SSID to current SSID */
- memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len;
netif_carrier_on(priv->dev);
@@ -487,7 +880,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
print_ssid(ssid, bss->ssid, bss->ssid_len),
priv->curbssparams.bssid,
- priv->curbssparams.channel);
+ priv->channel);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -560,7 +953,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
priv->adhoccreate = 0;
- priv->curbssparams.channel = bss->channel;
+ priv->channel = bss->channel;
/* Build the join command */
memset(&cmd, 0, sizeof(cmd));
@@ -633,11 +1026,6 @@ static int lbs_adhoc_join(struct lbs_private *priv,
}
}
- if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
- ret = -1;
- goto out;
- }
-
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
if (ret == 0) {
ret = lbs_adhoc_post(priv,
@@ -737,12 +1125,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
- if (lbs_create_dnld_countryinfo_11d(priv)) {
- lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n");
- ret = -1;
- goto out;
- }
-
lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
assoc_req->channel, assoc_req->band);
@@ -1099,7 +1481,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
/* else send START command */
lbs_deb_assoc("SSID not found, creating adhoc network\n");
memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
- IW_ESSID_MAX_SIZE);
+ IEEE80211_MAX_SSID_LEN);
assoc_req->bss.ssid_len = assoc_req->ssid_len;
lbs_adhoc_start(priv, assoc_req);
}
@@ -1185,7 +1567,8 @@ static int assoc_helper_mode(struct lbs_private *priv,
}
priv->mode = assoc_req->mode;
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode);
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
+ assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1205,7 +1588,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done;
}
- if (assoc_req->channel == priv->curbssparams.channel)
+ if (assoc_req->channel == priv->channel)
goto done;
if (priv->mesh_dev) {
@@ -1217,7 +1600,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
}
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
- priv->curbssparams.channel, assoc_req->channel);
+ priv->channel, assoc_req->channel);
ret = lbs_set_channel(priv, assoc_req->channel);
if (ret < 0)
@@ -1232,7 +1615,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done;
}
- if (assoc_req->channel != priv->curbssparams.channel) {
+ if (assoc_req->channel != priv->channel) {
lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
assoc_req->channel);
goto restore_mesh;
@@ -1253,7 +1636,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
restore_mesh:
if (priv->mesh_dev)
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel);
+ priv->channel);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1475,7 +1858,7 @@ static int should_stop_adhoc(struct lbs_private *priv,
}
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
- if (assoc_req->channel != priv->curbssparams.channel)
+ if (assoc_req->channel != priv->channel)
return 1;
}
@@ -1557,7 +1940,7 @@ static int lbs_find_best_network_ssid(struct lbs_private *priv,
found = lbs_find_best_ssid_in_list(priv, preferred_mode);
if (found && (found->ssid_len > 0)) {
- memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
*out_ssid_len = found->ssid_len;
*out_mode = found->mode;
ret = 0;
@@ -1775,12 +2158,12 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
assoc_req = priv->pending_assoc_req;
if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
- IW_ESSID_MAX_SIZE);
+ IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = priv->curbssparams.ssid_len;
}
if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
- assoc_req->channel = priv->curbssparams.channel;
+ assoc_req->channel = priv->channel;
if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
assoc_req->band = priv->curbssparams.band;
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 6e765e9f91a..40621b789fc 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -3,7 +3,126 @@
#ifndef _LBS_ASSOC_H_
#define _LBS_ASSOC_H_
-#include "dev.h"
+
+#include "defs.h"
+#include "host.h"
+
+
+struct lbs_private;
+
+/*
+ * In theory, the IE is limited to the IE length, 255,
+ * but in practice 64 bytes are enough.
+ */
+#define MAX_WPA_IE_LEN 64
+
+
+
+struct lbs_802_11_security {
+ u8 WPAenabled;
+ u8 WPA2enabled;
+ u8 wep_enabled;
+ u8 auth_mode;
+ u32 key_mgmt;
+};
+
+/** Current Basic Service Set State Structure */
+struct current_bss_params {
+ /** bssid */
+ u8 bssid[ETH_ALEN];
+ /** ssid */
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+
+ /** band */
+ u8 band;
+ /** channel is directly in priv->channel */
+ /** zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
+};
+
+/**
+ * @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+ u8 bssid[ETH_ALEN];
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+
+ u16 capability;
+ u32 rssi;
+ u32 channel;
+ u16 beaconperiod;
+ __le16 atimwindow;
+
+ /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
+ u8 mode;
+
+ /* zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
+
+ unsigned long last_scanned;
+
+ union ieee_phy_param_set phy;
+ union ieee_ss_param_set ss;
+
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+
+ u8 mesh;
+
+ struct list_head list;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID 1
+#define ASSOC_FLAG_CHANNEL 2
+#define ASSOC_FLAG_BAND 3
+#define ASSOC_FLAG_MODE 4
+#define ASSOC_FLAG_BSSID 5
+#define ASSOC_FLAG_WEP_KEYS 6
+#define ASSOC_FLAG_WEP_TX_KEYIDX 7
+#define ASSOC_FLAG_WPA_MCAST_KEY 8
+#define ASSOC_FLAG_WPA_UCAST_KEY 9
+#define ASSOC_FLAG_SECINFO 10
+#define ASSOC_FLAG_WPA_IE 11
+ unsigned long flags;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+ u8 channel;
+ u8 band;
+ u8 mode;
+ u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
+
+ /** WEP keys */
+ struct enc_key wep_keys[4];
+ u16 wep_tx_keyidx;
+
+ /** WPA keys */
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
+
+ struct lbs_802_11_security secinfo;
+
+ /** WPA Information Elements*/
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+
+ /* BSS to associate with for infrastructure of Ad-Hoc join */
+ struct bss_descriptor bss;
+};
+
+
+extern u8 lbs_bg_rates[MAX_RATES];
void lbs_association_worker(struct work_struct *work);
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
@@ -13,4 +132,24 @@ int lbs_adhoc_stop(struct lbs_private *priv);
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
u8 bssid[ETH_ALEN], u16 reason);
+int lbs_cmd_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *cmd);
+int lbs_ret_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action);
+int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc);
+
+int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
+ uint16_t *enable);
+
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc);
+
#endif /* _LBS_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
new file mode 100644
index 00000000000..4396dccd12a
--- /dev/null
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -0,0 +1,198 @@
+/*
+ * Implement cfg80211 ("iw") support.
+ *
+ * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany
+ * Holger Schurig <hs4233@mail.mn-solutions.de>
+ *
+ */
+
+#include <net/cfg80211.h>
+
+#include "cfg.h"
+#include "cmd.h"
+
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_channel lbs_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+#define RATETAB_ENT(_rate, _rateid, _flags) { \
+ .bitrate = (_rate), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+}
+
+
+static struct ieee80211_rate lbs_rates[] = {
+ RATETAB_ENT(10, 0x1, 0),
+ RATETAB_ENT(20, 0x2, 0),
+ RATETAB_ENT(55, 0x4, 0),
+ RATETAB_ENT(110, 0x8, 0),
+ RATETAB_ENT(60, 0x10, 0),
+ RATETAB_ENT(90, 0x20, 0),
+ RATETAB_ENT(120, 0x40, 0),
+ RATETAB_ENT(180, 0x80, 0),
+ RATETAB_ENT(240, 0x100, 0),
+ RATETAB_ENT(360, 0x200, 0),
+ RATETAB_ENT(480, 0x400, 0),
+ RATETAB_ENT(540, 0x800, 0),
+};
+
+static struct ieee80211_supported_band lbs_band_2ghz = {
+ .channels = lbs_2ghz_channels,
+ .n_channels = ARRAY_SIZE(lbs_2ghz_channels),
+ .bitrates = lbs_rates,
+ .n_bitrates = ARRAY_SIZE(lbs_rates),
+};
+
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+};
+
+
+
+static int lbs_cfg_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type);
+
+ if (channel_type != NL80211_CHAN_NO_HT)
+ goto out;
+
+ ret = lbs_set_channel(priv, chan->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+
+static struct cfg80211_ops lbs_cfg80211_ops = {
+ .set_channel = lbs_cfg_set_channel,
+};
+
+
+/*
+ * At this time lbs_private *priv doesn't even exist, so we just allocate
+ * memory and don't initialize the wiphy further. This is postponed until we
+ * can talk to the firmware and happens at registration time in
+ * lbs_cfg_wiphy_register().
+ */
+struct wireless_dev *lbs_cfg_alloc(struct device *dev)
+{
+ int ret = 0;
+ struct wireless_dev *wdev;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ dev_err(dev, "cannot allocate wireless device\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
+ if (!wdev->wiphy) {
+ dev_err(dev, "cannot allocate wiphy\n");
+ ret = -ENOMEM;
+ goto err_wiphy_new;
+ }
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return wdev;
+
+ err_wiphy_new:
+ kfree(wdev);
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ERR_PTR(ret);
+}
+
+
+/*
+ * This function get's called after lbs_setup_firmware() determined the
+ * firmware capabities. So we can setup the wiphy according to our
+ * hardware/firmware.
+ */
+int lbs_cfg_register(struct lbs_private *priv)
+{
+ struct wireless_dev *wdev = priv->wdev;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ wdev->wiphy->max_scan_ssids = 1;
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* TODO: BIT(NL80211_IFTYPE_ADHOC); */
+ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ /* TODO: honor priv->regioncode */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
+
+ /*
+ * We could check priv->fwcapinfo && FW_CAPINFO_WPA, but I have
+ * never seen a firmware without WPA
+ */
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+ ret = wiphy_register(wdev->wiphy);
+ if (ret < 0)
+ lbs_pr_err("cannot register wiphy device\n");
+
+ ret = register_netdev(priv->dev);
+ if (ret)
+ lbs_pr_err("cannot register network device\n");
+
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+void lbs_cfg_free(struct lbs_private *priv)
+{
+ struct wireless_dev *wdev = priv->wdev;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (!wdev)
+ return;
+
+ if (wdev->wiphy) {
+ wiphy_unregister(wdev->wiphy);
+ wiphy_free(wdev->wiphy);
+ }
+ kfree(wdev);
+}
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
new file mode 100644
index 00000000000..e09a193a34d
--- /dev/null
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -0,0 +1,16 @@
+#ifndef __LBS_CFG80211_H__
+#define __LBS_CFG80211_H__
+
+#include "dev.h"
+
+struct wireless_dev *lbs_cfg_alloc(struct device *dev);
+int lbs_cfg_register(struct lbs_private *priv);
+void lbs_cfg_free(struct lbs_private *priv);
+
+int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
+ u8 ssid_len);
+int lbs_scan_networks(struct lbs_private *priv, int full_scan);
+void lbs_cfg_scan_worker(struct work_struct *work);
+
+
+#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 685098148e1..1065ce29cd0 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -3,20 +3,21 @@
* It prepares command and sends it to firmware when it is ready.
*/
-#include <net/iw_handler.h>
#include <net/lib80211.h>
#include <linux/kfifo.h>
+#include <linux/sched.h>
+
#include "host.h"
-#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "assoc.h"
#include "wext.h"
+#include "scan.h"
#include "cmd.h"
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
/**
* @brief Simple callback that copies response back into command
@@ -76,6 +77,30 @@ static u8 is_command_allowed_in_ps(u16 cmd)
}
/**
+ * @brief This function checks if the command is allowed.
+ *
+ * @param priv A pointer to lbs_private structure
+ * @return allowed or not allowed.
+ */
+
+static int lbs_is_cmd_allowed(struct lbs_private *priv)
+{
+ int ret = 1;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("command not allowed in deep sleep\n");
+ ret = 0;
+ }
+ }
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+/**
* @brief Updates the hardware details like MAC address and regulatory region
*
* @param priv A pointer to struct lbs_private structure
@@ -168,11 +193,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
goto out;
}
- if (lbs_set_universaltable(priv, 0)) {
- ret = -1;
- goto out;
- }
-
out:
lbs_deb_leave(LBS_DEB_CMD);
return ret;
@@ -221,7 +241,7 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
psm->action = cpu_to_le16(cmd_action);
psm->multipledtim = 0;
switch (cmd_action) {
@@ -250,33 +270,6 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
return 0;
}
-int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
- uint16_t cmd_action, uint16_t *timeout)
-{
- struct cmd_ds_802_11_inactivity_timeout cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_SET)
- cmd.timeout = cpu_to_le16(*timeout);
- else
- cmd.timeout = 0;
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);
-
- if (!ret)
- *timeout = le16_to_cpu(cmd.timeout);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return 0;
-}
-
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp)
{
@@ -319,190 +312,53 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
return 0;
}
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
{
- struct cmd_ds_802_11_set_wep cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_ADD) {
- int i;
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
-
- /* Copy key types and material to host command structure */
- for (i = 0; i < 4; i++) {
- struct enc_key *pkey = &assoc->wep_keys[i];
-
- switch (pkey->len) {
- case KEY_LEN_WEP_40:
- cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
- break;
- case KEY_LEN_WEP_104:
- cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
- break;
- case 0:
- break;
- default:
- lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
- i, pkey->len);
- ret = -1;
- goto done;
- break;
- }
+ if (priv->is_deep_sleep) {
+ if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+ !priv->is_deep_sleep, (10 * HZ))) {
+ lbs_pr_err("ds_awake_q: timer expired\n");
+ ret = -1;
}
- } else if (cmd_action == CMD_ACT_REMOVE) {
- /* ACT_REMOVE clears _all_ WEP keys */
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
- lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable)
-{
- struct cmd_ds_802_11_enable_rsn cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_GET)
- cmd.enable = 0;
- else {
- if (*enable)
- cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
- else
- cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
- lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
}
- ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET)
- *enable = le16_to_cpu(cmd.enable);
-
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
- struct enc_key *key)
-{
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (key->flags & KEY_INFO_WPA_ENABLED)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
- if (key->flags & KEY_INFO_WPA_UNICAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
- if (key->flags & KEY_INFO_WPA_MCAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
-
- keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
- keyparam->keytypeid = cpu_to_le16(key->type);
- keyparam->keylen = cpu_to_le16(key->len);
- memcpy(keyparam->key, key->key, key->len);
-
- /* Length field doesn't include the {type,length} header */
- keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
{
- struct cmd_ds_802_11_key_material cmd;
- int ret = 0;
- int index = 0;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd.action = cpu_to_le16(cmd_action);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (cmd_action == CMD_ACT_GET) {
- cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
- } else {
- memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
-
- if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_unicast_key);
- index++;
- }
-
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_mcast_key);
- index++;
+ if (deep_sleep) {
+ if (priv->is_deep_sleep != 1) {
+ lbs_deb_cmd("deep sleep: sleep\n");
+ BUG_ON(!priv->enter_deep_sleep);
+ ret = priv->enter_deep_sleep(priv);
+ if (!ret) {
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+ }
+ } else {
+ lbs_pr_err("deep sleep: already enabled\n");
}
-
- /* The common header and as many keys as we included */
- cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
- keyParamSet[index]));
- }
- ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
- /* Copy the returned key to driver private data */
- if (!ret && cmd_action == CMD_ACT_GET) {
- void *buf_ptr = cmd.keyParamSet;
- void *resp_end = &(&cmd)[1];
-
- while (buf_ptr < resp_end) {
- struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
- struct enc_key *key;
- uint16_t param_set_len = le16_to_cpu(keyparam->length);
- uint16_t key_len = le16_to_cpu(keyparam->keylen);
- uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
- uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
- void *end;
-
- end = (void *)keyparam + sizeof(keyparam->type)
- + sizeof(keyparam->length) + param_set_len;
-
- /* Make sure we don't access past the end of the IEs */
- if (end > resp_end)
- break;
-
- if (key_flags & KEY_INFO_WPA_UNICAST)
- key = &priv->wpa_unicast_key;
- else if (key_flags & KEY_INFO_WPA_MCAST)
- key = &priv->wpa_mcast_key;
- else
- break;
-
- /* Copy returned key into driver */
- memset(key, 0, sizeof(struct enc_key));
- if (key_len > sizeof(key->key))
- break;
- key->type = key_type;
- key->flags = key_flags;
- key->len = key_len;
- memcpy(key->key, keyparam->key, key->len);
-
- buf_ptr = end + 1;
+ } else {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("deep sleep: wakeup\n");
+ BUG_ON(!priv->exit_deep_sleep);
+ ret = priv->exit_deep_sleep(priv);
+ if (!ret) {
+ ret = lbs_wait_for_ds_awake(priv);
+ if (ret)
+ lbs_pr_err("deep sleep: wakeup"
+ "failed\n");
+ }
}
}
@@ -534,7 +390,7 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
switch (oid) {
case SNMP_MIB_OID_BSS_TYPE:
cmd.bufsize = cpu_to_le16(sizeof(u8));
- cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1;
+ cmd.value[0] = val;
break;
case SNMP_MIB_OID_11D_ENABLE:
case SNMP_MIB_OID_FRAG_THRESHOLD:
@@ -587,13 +443,7 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
switch (le16_to_cpu(cmd.bufsize)) {
case sizeof(u8):
- if (oid == SNMP_MIB_OID_BSS_TYPE) {
- if (cmd.value[0] == 2)
- *out_val = IW_MODE_ADHOC;
- else
- *out_val = IW_MODE_INFRA;
- } else
- *out_val = cmd.value[0];
+ *out_val = cmd.value[0];
break;
case sizeof(u16):
*out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
@@ -680,7 +530,7 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
monitor->action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_SET) {
@@ -691,111 +541,6 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
return 0;
}
-static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
-{
-/* Bit Rate
-* 15:13 Reserved
-* 12 54 Mbps
-* 11 48 Mbps
-* 10 36 Mbps
-* 9 24 Mbps
-* 8 18 Mbps
-* 7 12 Mbps
-* 6 9 Mbps
-* 5 6 Mbps
-* 4 Reserved
-* 3 11 Mbps
-* 2 5.5 Mbps
-* 1 2 Mbps
-* 0 1 Mbps
-**/
-
- uint16_t ratemask;
- int i = lbs_data_rate_to_fw_index(rate);
- if (lower_rates_ok)
- ratemask = (0x1fef >> (12 - i));
- else
- ratemask = (1 << i);
- return cpu_to_le16(ratemask);
-}
-
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- uint16_t cmd_action)
-{
- struct cmd_ds_802_11_rate_adapt_rateset cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (!priv->cur_rate && !priv->enablehwauto)
- return -EINVAL;
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
- cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
- cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
- ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET) {
- priv->ratebitmap = le16_to_cpu(cmd.bitmap);
- priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
- }
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
-
-/**
- * @brief Set the data rate
- *
- * @param priv A pointer to struct lbs_private structure
- * @param rate The desired data rate, or 0 to clear a locked rate
- *
- * @return 0 on success, error on failure
- */
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
-{
- struct cmd_ds_802_11_data_rate cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (rate > 0) {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
- cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
- if (cmd.rates[0] == 0) {
- lbs_deb_cmd("DATA_RATE: invalid requested rate of"
- " 0x%02X\n", rate);
- ret = 0;
- goto out;
- }
- lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
- } else {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
- lbs_deb_cmd("DATA_RATE: setting auto\n");
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
- if (ret)
- goto out;
-
- lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
-
- /* FIXME: get actual rates FW can do if this command actually returns
- * all data rates supported.
- */
- priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
- lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
-
-out:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
/**
* @brief Get the radio channel
*
@@ -803,7 +548,7 @@ out:
*
* @return The channel on success, error on failure
*/
-int lbs_get_channel(struct lbs_private *priv)
+static int lbs_get_channel(struct lbs_private *priv)
{
struct cmd_ds_802_11_rf_channel cmd;
int ret = 0;
@@ -835,7 +580,7 @@ int lbs_update_channel(struct lbs_private *priv)
ret = lbs_get_channel(priv);
if (ret > 0) {
- priv->curbssparams.channel = ret;
+ priv->channel = ret;
ret = 0;
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -854,7 +599,7 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
struct cmd_ds_802_11_rf_channel cmd;
#ifdef DEBUG
- u8 old_channel = priv->curbssparams.channel;
+ u8 old_channel = priv->channel;
#endif
int ret = 0;
@@ -869,36 +614,15 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
if (ret)
goto out;
- priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
+ priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
- priv->curbssparams.channel);
+ priv->channel);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *cmd)
-{
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_RSSI);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
- cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
-
- /* reset Beacon SNR/NF/RSSI values */
- priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
u8 cmd_action, void *pdata_buf)
{
@@ -915,7 +639,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
macreg =
(struct cmd_ds_mac_reg_access *)&cmdptr->params.
macreg;
@@ -934,7 +658,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_bbp_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
bbpreg =
(struct cmd_ds_bbp_reg_access *)&cmdptr->params.
bbpreg;
@@ -953,7 +677,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_rf_reg_access) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
rfreg =
(struct cmd_ds_rf_reg_access *)&cmdptr->params.
rfreg;
@@ -980,7 +704,8 @@ static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_BT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
+ sizeof(struct cmd_header));
cmd->result = 0;
bt_access->action = cpu_to_le16(cmd_action);
@@ -1017,7 +742,8 @@ static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
+ sizeof(struct cmd_header));
cmd->result = 0;
if (pdata_buf)
@@ -1123,7 +849,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
ie->val.mesh_id_len = priv->mesh_ssid_len;
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
ie->len = sizeof(struct mrvl_meshie_val) -
- IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
+ IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
break;
case CMD_ACT_MESH_CONFIG_STOP:
@@ -1138,27 +864,6 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
-static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
-{
- struct cmd_ds_802_11_beacon_control
- *bcn_ctrl = &cmd->params.bcn_ctrl;
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
- + S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
-
- bcn_ctrl->action = cpu_to_le16(cmd_action);
- bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
- bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *cmdnode)
{
@@ -1242,8 +947,17 @@ static void lbs_submit_command(struct lbs_private *priv,
timeo = HZ/4;
}
- /* Setup the timer after transmit command */
- mod_timer(&priv->command_timer, jiffies + timeo);
+ if (command == CMD_802_11_DEEP_SLEEP) {
+ if (priv->is_auto_deep_sleep_enabled) {
+ priv->wakeup_dev_required = 1;
+ priv->dnld_sent = 0;
+ }
+ priv->is_deep_sleep = 1;
+ lbs_complete_command(priv, cmdnode, 0);
+ } else {
+ /* Setup the timer after transmit command */
+ mod_timer(&priv->command_timer, jiffies + timeo);
+ }
lbs_deb_leave(LBS_DEB_HOST);
}
@@ -1390,6 +1104,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
@@ -1440,7 +1159,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
cmdptr->command = cpu_to_le16(cmd_no);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.afc,
pdata_buf, sizeof(struct cmd_ds_802_11_afc));
@@ -1448,45 +1167,17 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = 0;
goto done;
- case CMD_802_11D_DOMAIN_INFO:
- ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
- cmd_no, cmd_action);
- break;
-
case CMD_802_11_TPC_CFG:
cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.tpccfg,
pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
ret = 0;
break;
- case CMD_802_11_LED_GPIO_CTRL:
- {
- struct mrvl_ie_ledgpio *gpio =
- (struct mrvl_ie_ledgpio*)
- cmdptr->params.ledgpio.data;
-
- memmove(&cmdptr->params.ledgpio,
- pdata_buf,
- sizeof(struct cmd_ds_802_11_led_ctrl));
-
- cmdptr->command =
- cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
-
-#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
- cmdptr->size =
- cpu_to_le16(le16_to_cpu(gpio->header.len)
- + S_DS_GEN
- + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
- gpio->header.len = gpio->header.len;
-
- ret = 0;
- break;
- }
case CMD_BT_ACCESS:
ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
@@ -1496,15 +1187,13 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
break;
- case CMD_GET_TSF:
- cmdptr->command = cpu_to_le16(CMD_GET_TSF);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
- S_DS_GEN);
- ret = 0;
- break;
case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
+ case CMD_802_11_DEEP_SLEEP:
+ cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
+ cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
+ break;
default:
lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
@@ -1822,30 +1511,6 @@ done:
return ret;
}
-void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
-{
- union iwreq_data iwrq;
- u8 buf[50];
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- memset(&iwrq, 0, sizeof(union iwreq_data));
- memset(buf, 0, sizeof(buf));
-
- snprintf(buf, sizeof(buf) - 1, "%s", str);
-
- iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
-
- /* Send Event to upper layer */
- lbs_deb_wext("event indication string %s\n", (char *)buf);
- lbs_deb_wext("event indication length %d\n", iwrq.data.length);
- lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
-
- wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
static void lbs_send_confirmsleep(struct lbs_private *priv)
{
unsigned long flags;
@@ -2023,7 +1688,7 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
}
-static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg)
@@ -2038,6 +1703,11 @@ static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ cmdnode = ERR_PTR(-EBUSY);
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
@@ -2116,5 +1786,3 @@ done:
return ret;
}
EXPORT_SYMBOL_GPL(__lbs_cmd);
-
-
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 392e578ca09..2862748aef7 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -3,11 +3,30 @@
#ifndef _LBS_CMD_H_
#define _LBS_CMD_H_
-#include "hostcmd.h"
+#include "host.h"
#include "dev.h"
+
+/* Command & response transfer between host and card */
+
+struct cmd_ctrl_node {
+ struct list_head list;
+ int result;
+ /* command response */
+ int (*callback)(struct lbs_private *,
+ unsigned long,
+ struct cmd_header *);
+ unsigned long callback_arg;
+ /* command data */
+ struct cmd_header *cmdbuf;
+ /* wait queue */
+ u16 cmdwaitqwoken;
+ wait_queue_head_t cmdwait_q;
+};
+
+
/* lbs_cmd() infers the size of the buffer to copy data back into, from
- the size of the target of the pointer. Since the command to be sent
+ the size of the target of the pointer. Since the command to be sent
may often be smaller, that size is set in cmd->size by the caller.*/
#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \
uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \
@@ -18,6 +37,11 @@
#define lbs_cmd_with_response(priv, cmdnr, cmd) \
lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
+int lbs_prepare_and_send_command(struct lbs_private *priv,
+ u16 cmd_no,
+ u16 cmd_action,
+ u16 wait_option, u32 cmd_oid, void *pdata_buf);
+
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size);
@@ -26,62 +50,93 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg);
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
- int8_t p1, int8_t p2);
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+ uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
+ int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+ unsigned long callback_arg);
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
- int8_t p2, int usesnr);
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+ struct cmd_header *resp);
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
- int8_t p1, int8_t p2);
+int lbs_allocate_cmd_buffer(struct lbs_private *priv);
+int lbs_free_cmd_buffer(struct lbs_private *priv);
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
- int8_t p2, int usesnr);
+int lbs_execute_next_command(struct lbs_private *priv);
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+ int result);
+int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
-int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
- struct cmd_header *resp);
-int lbs_update_hw_spec(struct lbs_private *priv);
+/* From cmdresp.c */
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
- struct cmd_ds_mesh_access *cmd);
+void lbs_mac_event_disconnected(struct lbs_private *priv);
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
-int lbs_get_channel(struct lbs_private *priv);
+
+/* Events */
+
+int lbs_process_event(struct lbs_private *priv, u32 event);
+
+
+/* Actual commands */
+
+int lbs_update_hw_spec(struct lbs_private *priv);
+
int lbs_set_channel(struct lbs_private *priv, u8 channel);
-int lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type);
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+int lbs_update_channel(struct lbs_private *priv);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct wol_config *p_wol_config);
-int lbs_suspend(struct lbs_private *priv);
-void lbs_resume(struct lbs_private *priv);
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- uint16_t cmd_action);
-int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
- uint16_t cmd_action, uint16_t *timeout);
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp);
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc);
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable);
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc);
-int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
- s16 *maxlevel);
-int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
+
+void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
+
+void lbs_ps_confirm_sleep(struct lbs_private *priv);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
+void lbs_set_mac_control(struct lbs_private *priv);
+
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+ s16 *maxlevel);
+
int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
+
+/* Mesh related */
+
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+ struct cmd_ds_mesh_access *cmd);
+
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type);
+
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+
+
+/* Commands only used in wext.c, assoc. and scan.c */
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+ int8_t p1, int8_t p2);
+
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+ int8_t p2, int usesnr);
+
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
+
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action);
+
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+
#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 23f684337fd..21d57690c20 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -11,6 +11,7 @@
#include "host.h"
#include "decl.h"
+#include "cmd.h"
#include "defs.h"
#include "dev.h"
#include "assoc.h"
@@ -26,23 +27,17 @@
*/
void lbs_mac_event_disconnected(struct lbs_private *priv)
{
- union iwreq_data wrqu;
-
if (priv->connect_status != LBS_CONNECTED)
return;
lbs_deb_enter(LBS_DEB_ASSOC);
- memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
/*
* Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
* It causes problem in the Supplicant
*/
-
msleep_interruptible(1000);
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ lbs_send_disconnect_notification(priv);
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
@@ -67,7 +62,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
* no longer valid.
*/
memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
- memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
+ memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = 0;
if (priv->psstate != PS_STATE_FULL_POWER) {
@@ -78,32 +73,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_ASSOC);
}
-/**
- * @brief This function handles MIC failure event.
- *
- * @param priv A pointer to struct lbs_private structure
- * @para event the event id
- * @return n/a
- */
-static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
-{
- char buf[50];
-
- lbs_deb_enter(LBS_DEB_CMD);
- memset(buf, 0, sizeof(buf));
-
- sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
-
- if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
- strcat(buf, "unicast ");
- } else {
- strcat(buf, "multicast ");
- }
-
- lbs_send_iwevcustom_event(priv, buf);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
static int lbs_ret_reg_access(struct lbs_private *priv,
u16 type, struct cmd_ds_command *resp)
{
@@ -147,53 +116,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
return ret;
}
-static int lbs_ret_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- /* store the non average value */
- priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
- priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
-
- priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
- priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor);
-
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
- priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
- priv->RSSI[TYPE_BEACON][TYPE_AVG] =
- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
- priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
-
- lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
- priv->RSSI[TYPE_BEACON][TYPE_AVG]);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_beacon_control *bcn_ctrl =
- &resp->params.bcn_ctrl;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (bcn_ctrl->action == CMD_ACT_GET) {
- priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
- priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
- }
-
- lbs_deb_enter(LBS_DEB_CMD);
- return 0;
-}
-
static inline int handle_cmd_response(struct lbs_private *priv,
struct cmd_header *cmd_response)
{
@@ -227,29 +149,13 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11_rssi(priv, resp);
break;
- case CMD_RET(CMD_802_11D_DOMAIN_INFO):
- ret = lbs_ret_802_11d_domain_info(resp);
- break;
-
case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&priv->driver_lock, flags);
memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
sizeof(struct cmd_ds_802_11_tpc_cfg));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
- case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
- spin_lock_irqsave(&priv->driver_lock, flags);
- memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
- sizeof(struct cmd_ds_802_11_led_ctrl));
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- break;
- case CMD_RET(CMD_GET_TSF):
- spin_lock_irqsave(&priv->driver_lock, flags);
- memcpy((void *)priv->cur_cmd->callback_arg,
- &resp->params.gettsf.tsfvalue, sizeof(u64));
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- break;
case CMD_RET(CMD_BT_ACCESS):
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd->callback_arg)
@@ -505,9 +411,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_HOST_AWAKE:
lbs_deb_cmd("EVENT: host awake\n");
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ priv->is_deep_sleep = 0;
lbs_send_confirmwake(priv);
break;
+ case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ lbs_deb_cmd("EVENT: ds awake\n");
+ priv->is_deep_sleep = 0;
+ priv->wakeup_dev_required = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ break;
+
case MACREG_INT_CODE_PS_AWAKE:
lbs_deb_cmd("EVENT: ps awake\n");
/* handle unexpected PS AWAKE event */
@@ -533,12 +451,12 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_MIC_ERR_UNICAST:
lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
- handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+ lbs_send_mic_failureevent(priv, event);
break;
case MACREG_INT_CODE_MIC_ERR_MULTICAST:
lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
- handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
+ lbs_send_mic_failureevent(priv, event);
break;
case MACREG_INT_CODE_MIB_CHANGED:
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 893a55ca344..587b0cb0088 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -451,10 +451,12 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
CMD_MAC_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+ if (!ret) {
+ pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
priv->mac_offset, priv->offsetvalue.value);
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
}
@@ -514,7 +516,8 @@ static ssize_t lbs_wrmac_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
@@ -539,10 +542,12 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
CMD_BBP_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+ if (!ret) {
+ pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
priv->bbp_offset, priv->offsetvalue.value);
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
@@ -603,7 +608,8 @@ static ssize_t lbs_wrbbp_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
@@ -628,10 +634,12 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
CMD_RF_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+ if (!ret) {
+ pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
priv->rf_offset, priv->offsetvalue.value);
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
@@ -692,7 +700,8 @@ static ssize_t lbs_wrrf_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 8b15380ae6e..678f7c9f750 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -8,71 +8,48 @@
#include <linux/netdevice.h>
-#include "defs.h"
-/** Function Prototype Declaration */
struct lbs_private;
struct sk_buff;
struct net_device;
-struct cmd_ctrl_node;
-struct cmd_ds_command;
-void lbs_set_mac_control(struct lbs_private *priv);
-void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
-
-int lbs_free_cmd_buffer(struct lbs_private *priv);
-
-int lbs_prepare_and_send_command(struct lbs_private *priv,
- u16 cmd_no,
- u16 cmd_action,
- u16 wait_option, u32 cmd_oid, void *pdata_buf);
+/* ethtool.c */
+extern const struct ethtool_ops lbs_ethtool_ops;
-int lbs_allocate_cmd_buffer(struct lbs_private *priv);
-int lbs_execute_next_command(struct lbs_private *priv);
-int lbs_process_event(struct lbs_private *priv, u32 event);
-void lbs_queue_event(struct lbs_private *priv, u32 event);
-void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
-u32 lbs_fw_index_to_data_rate(u8 index);
-u8 lbs_data_rate_to_fw_index(u32 rate);
-
-/** The proc fs interface */
-int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
-void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
- int result);
+/* tx.c */
+void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev);
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
+/* rx.c */
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
-void lbs_ps_confirm_sleep(struct lbs_private *priv);
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
-
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
- struct lbs_private *priv,
- u8 band,
- u16 channel);
-
-void lbs_mac_event_disconnected(struct lbs_private *priv);
-
-void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
/* persistcfg.c */
void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net);
+
/* main.c */
-struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
- int *cfp_no);
struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
void lbs_remove_card(struct lbs_private *priv);
int lbs_start_card(struct lbs_private *priv);
void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
-int lbs_update_channel(struct lbs_private *priv);
+int lbs_suspend(struct lbs_private *priv);
+void lbs_resume(struct lbs_private *priv);
+
+void lbs_queue_event(struct lbs_private *priv, u32 event);
+void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
+
+u32 lbs_fw_index_to_data_rate(u8 index);
+u8 lbs_data_rate_to_fw_index(u32 rate);
+
#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 72f3479a4d7..6b6ea9f7bf5 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -42,6 +42,7 @@
#define LBS_DEB_SDIO 0x00400000
#define LBS_DEB_SYSFS 0x00800000
#define LBS_DEB_SPI 0x01000000
+#define LBS_DEB_CFG80211 0x02000000
extern unsigned int lbs_debug;
@@ -86,6 +87,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
#define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
+#define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -320,7 +322,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
extern const char lbs_driver_version[];
extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
-extern u8 lbs_bg_rates[MAX_RATES];
/** ENUM definition*/
/** SNRNF_TYPE */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index d3b69a4b4b5..1a675111300 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -6,75 +6,10 @@
#ifndef _LBS_DEV_H_
#define _LBS_DEV_H_
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <linux/ethtool.h>
-#include <linux/debugfs.h>
+#include "scan.h"
+#include "assoc.h"
-#include "defs.h"
-#include "hostcmd.h"
-extern const struct ethtool_ops lbs_ethtool_ops;
-
-#define MAX_BSSID_PER_CHANNEL 16
-
-#define NR_TX_QUEUE 3
-
-/* For the extended Scan */
-#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
- MRVDRV_MAX_CHANNEL_SIZE + 1
-
-#define MAX_REGION_CHANNEL_NUM 2
-
-/** Chan-freq-TxPower mapping table*/
-struct chan_freq_power {
- /** channel Number */
- u16 channel;
- /** frequency of this channel */
- u32 freq;
- /** Max allowed Tx power level */
- u16 maxtxpower;
- /** TRUE:channel unsupported; FLASE:supported*/
- u8 unsupported;
-};
-
-/** region-band mapping table*/
-struct region_channel {
- /** TRUE if this entry is valid */
- u8 valid;
- /** region code for US, Japan ... */
- u8 region;
- /** band B/G/A, used for BAND_CONFIG cmd */
- u8 band;
- /** Actual No. of elements in the array below */
- u8 nrcfp;
- /** chan-freq-txpower mapping table*/
- struct chan_freq_power *CFP;
-};
-
-struct lbs_802_11_security {
- u8 WPAenabled;
- u8 WPA2enabled;
- u8 wep_enabled;
- u8 auth_mode;
- u32 key_mgmt;
-};
-
-/** Current Basic Service Set State Structure */
-struct current_bss_params {
- /** bssid */
- u8 bssid[ETH_ALEN];
- /** ssid */
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
-
- /** band */
- u8 band;
- /** channel */
- u8 channel;
- /** zero-terminated array of supported data rates */
- u8 rates[MAX_RATES + 1];
-};
/** sleep_params */
struct sleep_params {
@@ -100,95 +35,96 @@ struct lbs_mesh_stats {
/** Private structure for the MV device */
struct lbs_private {
- int mesh_open;
- int mesh_fw_ver;
- int infra_open;
- int mesh_autostart_enabled;
- char name[DEV_NAME_LEN];
-
- void *card;
+ /* Basic networking */
struct net_device *dev;
+ u32 connect_status;
+ int infra_open;
+ struct work_struct mcast_work;
+ u32 nr_of_multicastmacaddr;
+ u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+ /* CFG80211 */
+ struct wireless_dev *wdev;
+
+ /* Mesh */
struct net_device *mesh_dev; /* Virtual device */
+ u32 mesh_connect_status;
+ struct lbs_mesh_stats mstats;
+ int mesh_open;
+ int mesh_fw_ver;
+ int mesh_autostart_enabled;
+ uint16_t mesh_tlv;
+ u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 mesh_ssid_len;
+ struct work_struct sync_channel;
+
+ /* Monitor mode */
struct net_device *rtap_net_dev;
+ u32 monitormode;
- struct iw_statistics wstats;
- struct lbs_mesh_stats mstats;
+ /* Debugfs */
struct dentry *debugfs_dir;
struct dentry *debugfs_debug;
struct dentry *debugfs_files[6];
-
struct dentry *events_dir;
struct dentry *debugfs_events_files[6];
-
struct dentry *regs_dir;
struct dentry *debugfs_regs_files[6];
+ /* Hardware debugging */
u32 mac_offset;
u32 bbp_offset;
u32 rf_offset;
+ struct lbs_offset_value offsetvalue;
- /* Download sent:
- bit0 1/0=data_sent/data_tx_done,
- bit1 1/0=cmd_sent/cmd_tx_done,
- all other bits reserved 0 */
- u8 dnld_sent;
-
- /** thread to service interrupts */
- struct task_struct *main_thread;
- wait_queue_head_t waitq;
- struct workqueue_struct *work_thread;
+ /* Power management */
+ u16 psmode;
+ u32 psstate;
+ u8 needtowakeup;
- struct work_struct mcast_work;
+ /* Deep sleep */
+ int is_deep_sleep;
+ int is_auto_deep_sleep_enabled;
+ int wakeup_dev_required;
+ int is_activity_detected;
+ int auto_deep_sleep_timeout; /* in ms */
+ wait_queue_head_t ds_awake_q;
+ struct timer_list auto_deepsleep_timer;
- /** Scanning */
- struct delayed_work scan_work;
- struct delayed_work assoc_work;
- struct work_struct sync_channel;
- /* remember which channel was scanned last, != 0 if currently scanning */
- int scan_channel;
- u8 scan_ssid[IW_ESSID_MAX_SIZE + 1];
- u8 scan_ssid_len;
-
- /** Hardware access */
+ /* Hardware access */
+ void *card;
+ u8 fw_ready;
+ u8 surpriseremoved;
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
+ int (*enter_deep_sleep) (struct lbs_private *priv);
+ int (*exit_deep_sleep) (struct lbs_private *priv);
+ int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
- /* Wake On LAN */
- uint32_t wol_criteria;
- uint8_t wol_gpio;
- uint8_t wol_gap;
-
- /** Wlan adapter data structure*/
- /** STATUS variables */
+ /* Adapter info (from EEPROM) */
u32 fwrelease;
u32 fwcapinfo;
+ u16 regioncode;
+ u8 current_addr[ETH_ALEN];
- struct mutex lock;
-
- /* TX packet ready to be sent... */
- int tx_pending_len; /* -1 while building packet */
-
- u8 tx_pending_buf[LBS_UPLD_SIZE];
- /* protected by hard_start_xmit serialization */
-
- /** command-related variables */
+ /* Command download */
+ u8 dnld_sent;
+ /* bit0 1/0=data_sent/data_tx_done,
+ bit1 1/0=cmd_sent/cmd_tx_done,
+ all other bits reserved 0 */
u16 seqnum;
-
struct cmd_ctrl_node *cmd_array;
- /** Current command */
struct cmd_ctrl_node *cur_cmd;
- int cur_cmd_retcode;
- /** command Queues */
- /** Free command buffers */
- struct list_head cmdfreeq;
- /** Pending command buffers */
- struct list_head cmdpendingq;
-
+ struct list_head cmdfreeq; /* free command buffers */
+ struct list_head cmdpendingq; /* pending command buffers */
wait_queue_head_t cmd_pending;
+ struct timer_list command_timer;
+ int nr_retries;
+ int cmd_timed_out;
/* Command responses sent from the hardware to the driver */
+ int cur_cmd_retcode;
u8 resp_idx;
u8 resp_buf[2][LBS_UPLD_SIZE];
u32 resp_len[2];
@@ -196,95 +132,76 @@ struct lbs_private {
/* Events sent from hardware to driver */
struct kfifo *event_fifo;
- /* nickname */
- u8 nodename[16];
-
- /** spin locks */
- spinlock_t driver_lock;
-
- /** Timers */
- struct timer_list command_timer;
- int nr_retries;
- int cmd_timed_out;
-
- /** current ssid/bssid related parameters*/
- struct current_bss_params curbssparams;
-
- uint16_t mesh_tlv;
- u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
- u8 mesh_ssid_len;
-
- /* IW_MODE_* */
- u8 mode;
-
- /* Scan results list */
- struct list_head network_list;
- struct list_head network_free_list;
- struct bss_descriptor *networks;
-
- u16 beacon_period;
- u8 beacon_enable;
- u8 adhoccreate;
-
- /** capability Info used in Association, start, join */
- u16 capability;
-
- /** MAC address information */
- u8 current_addr[ETH_ALEN];
- u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
- u32 nr_of_multicastmacaddr;
+ /** thread to service interrupts */
+ struct task_struct *main_thread;
+ wait_queue_head_t waitq;
+ struct workqueue_struct *work_thread;
- /** 802.11 statistics */
-// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+ /** Encryption stuff */
+ struct lbs_802_11_security secinfo;
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+ u16 wep_tx_keyidx;
+ struct enc_key wep_keys[4];
- uint16_t enablehwauto;
- uint16_t ratebitmap;
+ /* Wake On LAN */
+ uint32_t wol_criteria;
+ uint8_t wol_gpio;
+ uint8_t wol_gap;
+ /* Transmitting */
+ int tx_pending_len; /* -1 while building packet */
+ u8 tx_pending_buf[LBS_UPLD_SIZE];
+ /* protected by hard_start_xmit serialization */
u8 txretrycount;
-
- /** Tx-related variables (for single packet tx) */
struct sk_buff *currenttxskb;
- /** NIC Operation characteristics */
+ /* Locks */
+ struct mutex lock;
+ spinlock_t driver_lock;
+
+ /* NIC/link operation characteristics */
u16 mac_control;
- u32 connect_status;
- u32 mesh_connect_status;
- u16 regioncode;
+ u8 radio_on;
+ u8 channel;
s16 txpower_cur;
s16 txpower_min;
s16 txpower_max;
- /** POWER MANAGEMENT AND PnP SUPPORT */
- u8 surpriseremoved;
-
- u16 psmode; /* Wlan802_11PowermodeCAM=disable
- Wlan802_11PowermodeMAX_PSP=enable */
- u32 psstate;
- u8 needtowakeup;
+ /** Scanning */
+ struct delayed_work scan_work;
+ int scan_channel;
+ /* remember which channel was scanned last, != 0 if currently scanning */
+ u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 scan_ssid_len;
+ /* Associating */
+ struct delayed_work assoc_work;
+ struct current_bss_params curbssparams;
+ u8 mode;
+ struct list_head network_list;
+ struct list_head network_free_list;
+ struct bss_descriptor *networks;
struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req;
+ u16 capability;
+ uint16_t enablehwauto;
+ uint16_t ratebitmap;
- /** Encryption parameter */
- struct lbs_802_11_security secinfo;
-
- /** WEP keys */
- struct enc_key wep_keys[4];
- u16 wep_tx_keyidx;
-
- /** WPA keys */
- struct enc_key wpa_mcast_key;
- struct enc_key wpa_unicast_key;
-
-/*
- * In theory, the IE is limited to the IE length, 255,
- * but in practice 64 bytes are enough.
- */
-#define MAX_WPA_IE_LEN 64
+ /* ADHOC */
+ u16 beacon_period;
+ u8 beacon_enable;
+ u8 adhoccreate;
- /** WPA Information Elements*/
- u8 wpa_ie[MAX_WPA_IE_LEN];
- u8 wpa_ie_len;
+ /* WEXT */
+ char name[DEV_NAME_LEN];
+ u8 nodename[16];
+ struct iw_statistics wstats;
+ u8 cur_rate;
+#define MAX_REGION_CHANNEL_NUM 2
+ struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
/** Requested Signal Strength*/
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
@@ -294,116 +211,8 @@ struct lbs_private {
u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
u16 nextSNRNF;
u16 numSNRNF;
-
- u8 radio_on;
-
- /** data rate stuff */
- u8 cur_rate;
-
- /** RF calibration data */
-
-#define MAX_REGION_CHANNEL_NUM 2
- /** region channel data */
- struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
-
- struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
-
- /** 11D and Domain Regulatory Data */
- struct lbs_802_11d_domain_reg domainreg;
- struct parsed_region_chan_11d parsed_region_chan;
-
- /** FSM variable for 11d support */
- u32 enable11d;
-
- /** MISCELLANEOUS */
- struct lbs_offset_value offsetvalue;
-
- u32 monitormode;
- u8 fw_ready;
};
extern struct cmd_confirm_sleep confirm_sleep;
-/**
- * @brief Structure used to store information for each beacon/probe response
- */
-struct bss_descriptor {
- u8 bssid[ETH_ALEN];
-
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
-
- u16 capability;
- u32 rssi;
- u32 channel;
- u16 beaconperiod;
- __le16 atimwindow;
-
- /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
- u8 mode;
-
- /* zero-terminated array of supported data rates */
- u8 rates[MAX_RATES + 1];
-
- unsigned long last_scanned;
-
- union ieee_phy_param_set phy;
- union ieee_ss_param_set ss;
-
- struct ieee_ie_country_info_full_set countryinfo;
-
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
-
- u8 mesh;
-
- struct list_head list;
-};
-
-/** Association request
- *
- * Encapsulates all the options that describe a specific assocation request
- * or configuration of the wireless card's radio, mode, and security settings.
- */
-struct assoc_request {
-#define ASSOC_FLAG_SSID 1
-#define ASSOC_FLAG_CHANNEL 2
-#define ASSOC_FLAG_BAND 3
-#define ASSOC_FLAG_MODE 4
-#define ASSOC_FLAG_BSSID 5
-#define ASSOC_FLAG_WEP_KEYS 6
-#define ASSOC_FLAG_WEP_TX_KEYIDX 7
-#define ASSOC_FLAG_WPA_MCAST_KEY 8
-#define ASSOC_FLAG_WPA_UCAST_KEY 9
-#define ASSOC_FLAG_SECINFO 10
-#define ASSOC_FLAG_WPA_IE 11
- unsigned long flags;
-
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
- u8 channel;
- u8 band;
- u8 mode;
- u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
-
- /** WEP keys */
- struct enc_key wep_keys[4];
- u16 wep_tx_keyidx;
-
- /** WPA keys */
- struct enc_key wpa_mcast_key;
- struct enc_key wpa_unicast_key;
-
- struct lbs_802_11_security secinfo;
-
- /** WPA Information Elements*/
- u8 wpa_ie[MAX_WPA_IE_LEN];
- u8 wpa_ie_len;
-
- /* BSS to associate with for infrastructure of Ad-Hoc join */
- struct bss_descriptor bss;
-};
-
#endif
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index fe8f0cb737b..3809c0b4946 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -1,201 +1,190 @@
/**
- * This file contains definitions of WLAN commands.
+ * This file function prototypes, data structure
+ * and definitions for all the host/station commands
*/
#ifndef _LBS_HOST_H_
#define _LBS_HOST_H_
-/** PUBLIC DEFINITIONS */
-#define DEFAULT_AD_HOC_CHANNEL 6
-#define DEFAULT_AD_HOC_CHANNEL_A 36
+#include "types.h"
+#include "defs.h"
-#define CMD_OPTION_WAITFORRSP 0x0002
+#define DEFAULT_AD_HOC_CHANNEL 6
+
+#define CMD_OPTION_WAITFORRSP 0x0002
/** Host command IDs */
/* Return command are almost always the same as the host command, but with
* bit 15 set high. There are a few exceptions, though...
*/
-#define CMD_RET(cmd) (0x8000 | cmd)
+#define CMD_RET(cmd) (0x8000 | cmd)
/* Return command convention exceptions: */
-#define CMD_RET_802_11_ASSOCIATE 0x8012
+#define CMD_RET_802_11_ASSOCIATE 0x8012
/* Command codes */
-#define CMD_GET_HW_SPEC 0x0003
-#define CMD_EEPROM_UPDATE 0x0004
-#define CMD_802_11_RESET 0x0005
-#define CMD_802_11_SCAN 0x0006
-#define CMD_802_11_GET_LOG 0x000b
-#define CMD_MAC_MULTICAST_ADR 0x0010
-#define CMD_802_11_AUTHENTICATE 0x0011
-#define CMD_802_11_EEPROM_ACCESS 0x0059
-#define CMD_802_11_ASSOCIATE 0x0050
-#define CMD_802_11_SET_WEP 0x0013
-#define CMD_802_11_GET_STAT 0x0014
-#define CMD_802_3_GET_STAT 0x0015
-#define CMD_802_11_SNMP_MIB 0x0016
-#define CMD_MAC_REG_MAP 0x0017
-#define CMD_BBP_REG_MAP 0x0018
-#define CMD_MAC_REG_ACCESS 0x0019
-#define CMD_BBP_REG_ACCESS 0x001a
-#define CMD_RF_REG_ACCESS 0x001b
-#define CMD_802_11_RADIO_CONTROL 0x001c
-#define CMD_802_11_RF_CHANNEL 0x001d
-#define CMD_802_11_RF_TX_POWER 0x001e
-#define CMD_802_11_RSSI 0x001f
-#define CMD_802_11_RF_ANTENNA 0x0020
-#define CMD_802_11_PS_MODE 0x0021
-#define CMD_802_11_DATA_RATE 0x0022
-#define CMD_RF_REG_MAP 0x0023
-#define CMD_802_11_DEAUTHENTICATE 0x0024
-#define CMD_802_11_REASSOCIATE 0x0025
-#define CMD_MAC_CONTROL 0x0028
-#define CMD_802_11_AD_HOC_START 0x002b
-#define CMD_802_11_AD_HOC_JOIN 0x002c
-#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
-#define CMD_802_11_ENABLE_RSN 0x002f
-#define CMD_802_11_SET_AFC 0x003c
-#define CMD_802_11_GET_AFC 0x003d
-#define CMD_802_11_AD_HOC_STOP 0x0040
-#define CMD_802_11_HOST_SLEEP_CFG 0x0043
-#define CMD_802_11_WAKEUP_CONFIRM 0x0044
-#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045
-#define CMD_802_11_BEACON_STOP 0x0049
-#define CMD_802_11_MAC_ADDRESS 0x004d
-#define CMD_802_11_LED_GPIO_CTRL 0x004e
-#define CMD_802_11_EEPROM_ACCESS 0x0059
-#define CMD_802_11_BAND_CONFIG 0x0058
-#define CMD_GSPI_BUS_CONFIG 0x005a
-#define CMD_802_11D_DOMAIN_INFO 0x005b
-#define CMD_802_11_KEY_MATERIAL 0x005e
-#define CMD_802_11_SLEEP_PARAMS 0x0066
-#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
-#define CMD_802_11_SLEEP_PERIOD 0x0068
-#define CMD_802_11_TPC_CFG 0x0072
-#define CMD_802_11_PA_CFG 0x0073
-#define CMD_802_11_FW_WAKE_METHOD 0x0074
-#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
-#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
-#define CMD_802_11_TX_RATE_QUERY 0x007f
-#define CMD_GET_TSF 0x0080
-#define CMD_BT_ACCESS 0x0087
-#define CMD_FWT_ACCESS 0x0095
-#define CMD_802_11_MONITOR_MODE 0x0098
-#define CMD_MESH_ACCESS 0x009b
-#define CMD_MESH_CONFIG_OLD 0x00a3
-#define CMD_MESH_CONFIG 0x00ac
-#define CMD_SET_BOOT2_VER 0x00a5
-#define CMD_FUNC_INIT 0x00a9
-#define CMD_FUNC_SHUTDOWN 0x00aa
-#define CMD_802_11_BEACON_CTRL 0x00b0
+#define CMD_GET_HW_SPEC 0x0003
+#define CMD_EEPROM_UPDATE 0x0004
+#define CMD_802_11_RESET 0x0005
+#define CMD_802_11_SCAN 0x0006
+#define CMD_802_11_GET_LOG 0x000b
+#define CMD_MAC_MULTICAST_ADR 0x0010
+#define CMD_802_11_AUTHENTICATE 0x0011
+#define CMD_802_11_EEPROM_ACCESS 0x0059
+#define CMD_802_11_ASSOCIATE 0x0050
+#define CMD_802_11_SET_WEP 0x0013
+#define CMD_802_11_GET_STAT 0x0014
+#define CMD_802_3_GET_STAT 0x0015
+#define CMD_802_11_SNMP_MIB 0x0016
+#define CMD_MAC_REG_MAP 0x0017
+#define CMD_BBP_REG_MAP 0x0018
+#define CMD_MAC_REG_ACCESS 0x0019
+#define CMD_BBP_REG_ACCESS 0x001a
+#define CMD_RF_REG_ACCESS 0x001b
+#define CMD_802_11_RADIO_CONTROL 0x001c
+#define CMD_802_11_RF_CHANNEL 0x001d
+#define CMD_802_11_RF_TX_POWER 0x001e
+#define CMD_802_11_RSSI 0x001f
+#define CMD_802_11_RF_ANTENNA 0x0020
+#define CMD_802_11_PS_MODE 0x0021
+#define CMD_802_11_DATA_RATE 0x0022
+#define CMD_RF_REG_MAP 0x0023
+#define CMD_802_11_DEAUTHENTICATE 0x0024
+#define CMD_802_11_REASSOCIATE 0x0025
+#define CMD_MAC_CONTROL 0x0028
+#define CMD_802_11_AD_HOC_START 0x002b
+#define CMD_802_11_AD_HOC_JOIN 0x002c
+#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
+#define CMD_802_11_ENABLE_RSN 0x002f
+#define CMD_802_11_SET_AFC 0x003c
+#define CMD_802_11_GET_AFC 0x003d
+#define CMD_802_11_DEEP_SLEEP 0x003e
+#define CMD_802_11_AD_HOC_STOP 0x0040
+#define CMD_802_11_HOST_SLEEP_CFG 0x0043
+#define CMD_802_11_WAKEUP_CONFIRM 0x0044
+#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045
+#define CMD_802_11_BEACON_STOP 0x0049
+#define CMD_802_11_MAC_ADDRESS 0x004d
+#define CMD_802_11_LED_GPIO_CTRL 0x004e
+#define CMD_802_11_EEPROM_ACCESS 0x0059
+#define CMD_802_11_BAND_CONFIG 0x0058
+#define CMD_GSPI_BUS_CONFIG 0x005a
+#define CMD_802_11D_DOMAIN_INFO 0x005b
+#define CMD_802_11_KEY_MATERIAL 0x005e
+#define CMD_802_11_SLEEP_PARAMS 0x0066
+#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
+#define CMD_802_11_SLEEP_PERIOD 0x0068
+#define CMD_802_11_TPC_CFG 0x0072
+#define CMD_802_11_PA_CFG 0x0073
+#define CMD_802_11_FW_WAKE_METHOD 0x0074
+#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
+#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
+#define CMD_802_11_TX_RATE_QUERY 0x007f
+#define CMD_GET_TSF 0x0080
+#define CMD_BT_ACCESS 0x0087
+#define CMD_FWT_ACCESS 0x0095
+#define CMD_802_11_MONITOR_MODE 0x0098
+#define CMD_MESH_ACCESS 0x009b
+#define CMD_MESH_CONFIG_OLD 0x00a3
+#define CMD_MESH_CONFIG 0x00ac
+#define CMD_SET_BOOT2_VER 0x00a5
+#define CMD_FUNC_INIT 0x00a9
+#define CMD_FUNC_SHUTDOWN 0x00aa
+#define CMD_802_11_BEACON_CTRL 0x00b0
/* For the IEEE Power Save */
-#define CMD_SUBCMD_ENTER_PS 0x0030
-#define CMD_SUBCMD_EXIT_PS 0x0031
-#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
-#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
-#define CMD_SUBCMD_FULL_POWERUP 0x0036
+#define CMD_SUBCMD_ENTER_PS 0x0030
+#define CMD_SUBCMD_EXIT_PS 0x0031
+#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
+#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
+#define CMD_SUBCMD_FULL_POWERUP 0x0036
-#define CMD_ENABLE_RSN 0x0001
-#define CMD_DISABLE_RSN 0x0000
+#define CMD_ENABLE_RSN 0x0001
+#define CMD_DISABLE_RSN 0x0000
-#define CMD_ACT_GET 0x0000
-#define CMD_ACT_SET 0x0001
-#define CMD_ACT_GET_AES 0x0002
-#define CMD_ACT_SET_AES 0x0003
-#define CMD_ACT_REMOVE_AES 0x0004
+#define CMD_ACT_GET 0x0000
+#define CMD_ACT_SET 0x0001
/* Define action or option for CMD_802_11_SET_WEP */
-#define CMD_ACT_ADD 0x0002
-#define CMD_ACT_REMOVE 0x0004
-#define CMD_ACT_USE_DEFAULT 0x0008
-
-#define CMD_TYPE_WEP_40_BIT 0x01
-#define CMD_TYPE_WEP_104_BIT 0x02
+#define CMD_ACT_ADD 0x0002
+#define CMD_ACT_REMOVE 0x0004
-#define CMD_NUM_OF_WEP_KEYS 4
+#define CMD_TYPE_WEP_40_BIT 0x01
+#define CMD_TYPE_WEP_104_BIT 0x02
-#define CMD_WEP_KEY_INDEX_MASK 0x3fff
+#define CMD_NUM_OF_WEP_KEYS 4
-/* Define action or option for CMD_802_11_RESET */
-#define CMD_ACT_HALT 0x0003
+#define CMD_WEP_KEY_INDEX_MASK 0x3fff
/* Define action or option for CMD_802_11_SCAN */
-#define CMD_BSS_TYPE_BSS 0x0001
-#define CMD_BSS_TYPE_IBSS 0x0002
-#define CMD_BSS_TYPE_ANY 0x0003
+#define CMD_BSS_TYPE_BSS 0x0001
+#define CMD_BSS_TYPE_IBSS 0x0002
+#define CMD_BSS_TYPE_ANY 0x0003
/* Define action or option for CMD_802_11_SCAN */
-#define CMD_SCAN_TYPE_ACTIVE 0x0000
-#define CMD_SCAN_TYPE_PASSIVE 0x0001
+#define CMD_SCAN_TYPE_ACTIVE 0x0000
+#define CMD_SCAN_TYPE_PASSIVE 0x0001
-#define CMD_SCAN_RADIO_TYPE_BG 0
+#define CMD_SCAN_RADIO_TYPE_BG 0
-#define CMD_SCAN_PROBE_DELAY_TIME 0
+#define CMD_SCAN_PROBE_DELAY_TIME 0
/* Define action or option for CMD_MAC_CONTROL */
-#define CMD_ACT_MAC_RX_ON 0x0001
-#define CMD_ACT_MAC_TX_ON 0x0002
-#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
-#define CMD_ACT_MAC_WEP_ENABLE 0x0008
-#define CMD_ACT_MAC_INT_ENABLE 0x0010
-#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
-#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
-#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
-#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
-#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
+#define CMD_ACT_MAC_RX_ON 0x0001
+#define CMD_ACT_MAC_TX_ON 0x0002
+#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
+#define CMD_ACT_MAC_WEP_ENABLE 0x0008
+#define CMD_ACT_MAC_INT_ENABLE 0x0010
+#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
-#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
-#define CMD_SUBSCRIBE_SNR_LOW 0x0002
-#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
-#define CMD_SUBSCRIBE_BCNMISS 0x0008
-#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
-#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
+#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
+#define CMD_SUBSCRIBE_SNR_LOW 0x0002
+#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
+#define CMD_SUBSCRIBE_BCNMISS 0x0008
+#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
+#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
-#define RADIO_PREAMBLE_LONG 0x00
-#define RADIO_PREAMBLE_SHORT 0x02
-#define RADIO_PREAMBLE_AUTO 0x04
+#define RADIO_PREAMBLE_LONG 0x00
+#define RADIO_PREAMBLE_SHORT 0x02
+#define RADIO_PREAMBLE_AUTO 0x04
/* Define action or option for CMD_802_11_RF_CHANNEL */
-#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
-#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
+#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
/* Define action or option for CMD_802_11_DATA_RATE */
-#define CMD_ACT_SET_TX_AUTO 0x0000
-#define CMD_ACT_SET_TX_FIX_RATE 0x0001
-#define CMD_ACT_GET_TX_RATE 0x0002
-
-#define CMD_ACT_SET_RX 0x0001
-#define CMD_ACT_SET_TX 0x0002
-#define CMD_ACT_SET_BOTH 0x0003
-#define CMD_ACT_GET_RX 0x0004
-#define CMD_ACT_GET_TX 0x0008
-#define CMD_ACT_GET_BOTH 0x000c
+#define CMD_ACT_SET_TX_AUTO 0x0000
+#define CMD_ACT_SET_TX_FIX_RATE 0x0001
+#define CMD_ACT_GET_TX_RATE 0x0002
/* Define action or option for CMD_802_11_PS_MODE */
-#define CMD_TYPE_CAM 0x0000
-#define CMD_TYPE_MAX_PSP 0x0001
-#define CMD_TYPE_FAST_PSP 0x0002
+#define CMD_TYPE_CAM 0x0000
+#define CMD_TYPE_MAX_PSP 0x0001
+#define CMD_TYPE_FAST_PSP 0x0002
/* Options for CMD_802_11_FW_WAKE_METHOD */
-#define CMD_WAKE_METHOD_UNCHANGED 0x0000
-#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
-#define CMD_WAKE_METHOD_GPIO 0x0002
+#define CMD_WAKE_METHOD_UNCHANGED 0x0000
+#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
+#define CMD_WAKE_METHOD_GPIO 0x0002
/* Object IDs for CMD_802_11_SNMP_MIB */
-#define SNMP_MIB_OID_BSS_TYPE 0x0000
-#define SNMP_MIB_OID_OP_RATE_SET 0x0001
-#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */
-#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */
-#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */
-#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005
-#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006
-#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007
-#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008
-#define SNMP_MIB_OID_11D_ENABLE 0x0009
-#define SNMP_MIB_OID_11H_ENABLE 0x000A
+#define SNMP_MIB_OID_BSS_TYPE 0x0000
+#define SNMP_MIB_OID_OP_RATE_SET 0x0001
+#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */
+#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */
+#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */
+#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005
+#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006
+#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007
+#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008
+#define SNMP_MIB_OID_11D_ENABLE 0x0009
+#define SNMP_MIB_OID_11H_ENABLE 0x000A
/* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts {
@@ -302,4 +291,672 @@ enum cmd_mesh_config_types {
#define MACREG_INT_CODE_MESH_AUTO_STARTED 35
#define MACREG_INT_CODE_FIRMWARE_READY 48
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Tx packet status */
+ __le32 tx_status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ /* Reserved */
+ __le16 reserved;
+ } bss;
+ } u;
+ /* Tx control */
+ __le32 tx_control;
+ __le32 tx_packet_location;
+ /* Tx packet length */
+ __le16 tx_packet_length;
+ /* First 2 byte of destination MAC address */
+ u8 tx_dest_addr_high[2];
+ /* Last 4 byte of destination MAC address */
+ u8 tx_dest_addr_low[4];
+ /* Pkt Priority */
+ u8 priority;
+ /* Pkt Trasnit Power control */
+ u8 powermgmt;
+ /* Amount of time the packet has been queued (units = 2ms) */
+ u8 pktdelay_2ms;
+ /* reserved */
+ u8 reserved1;
+} __attribute__ ((packed));
+
+/* RxPD Descriptor */
+struct rxpd {
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Rx packet status */
+ __le16 status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ } __attribute__ ((packed)) bss;
+ } __attribute__ ((packed)) u;
+
+ /* SNR */
+ u8 snr;
+
+ /* Tx control */
+ u8 rx_control;
+
+ /* Pkt length */
+ __le16 pkt_len;
+
+ /* Noise Floor */
+ u8 nf;
+
+ /* Rx Packet Rate */
+ u8 rx_rate;
+
+ /* Pkt addr */
+ __le32 pkt_ptr;
+
+ /* Next Rx RxPD addr */
+ __le32 next_rxpd_ptr;
+
+ /* Pkt Priority */
+ u8 priority;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_header {
+ __le16 command;
+ __le16 size;
+ __le16 seqnum;
+ __le16 result;
+} __attribute__ ((packed));
+
+/* Generic structure to hold all key types. */
+struct enc_key {
+ u16 len;
+ u16 flags; /* KEY_INFO_* from defs.h */
+ u16 type; /* KEY_TYPE_* from defs.h */
+ u8 key[32];
+};
+
+/* lbs_offset_value */
+struct lbs_offset_value {
+ u32 offset;
+ u32 value;
+} __attribute__ ((packed));
+
+/*
+ * Define data structure for CMD_GET_HW_SPEC
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+ struct cmd_header hdr;
+
+ /* HW Interface version number */
+ __le16 hwifversion;
+ /* HW version number */
+ __le16 version;
+ /* Max number of TxPD FW can handle */
+ __le16 nr_txpd;
+ /* Max no of Multicast address */
+ __le16 nr_mcast_adr;
+ /* MAC address */
+ u8 permanentaddr[6];
+
+ /* region Code */
+ __le16 regioncode;
+
+ /* Number of antenna used */
+ __le16 nr_antenna;
+
+ /* FW release number, example 0x01030304 = 2.3.4p1 */
+ __le32 fwrelease;
+
+ /* Base Address of TxPD queue */
+ __le32 wcb_base;
+ /* Read Pointer of RxPd queue */
+ __le32 rxpd_rdptr;
+
+ /* Write Pointer of RxPd queue */
+ __le32 rxpd_wrptr;
+
+ /*FW/HW capability */
+ __le32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_subscribe_event {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 events;
+
+ /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
+ * number of TLVs. From the v5.1 manual, those TLVs would add up to
+ * 40 bytes. However, future firmware might add additional TLVs, so I
+ * bump this up a bit.
+ */
+ uint8_t tlv[128];
+} __attribute__ ((packed));
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for CMD_802_11_SCAN
+ */
+struct cmd_ds_802_11_scan {
+ struct cmd_header hdr;
+
+ uint8_t bsstype;
+ uint8_t bssid[ETH_ALEN];
+ uint8_t tlvbuffer[0];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_scan_rsp {
+ struct cmd_header hdr;
+
+ __le16 bssdescriptsize;
+ uint8_t nr_sets;
+ uint8_t bssdesc_and_tlvbuffer[0];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_get_log {
+ struct cmd_header hdr;
+
+ __le32 mcasttxframe;
+ __le32 failed;
+ __le32 retry;
+ __le32 multiretry;
+ __le32 framedup;
+ __le32 rtssuccess;
+ __le32 rtsfailure;
+ __le32 ackfailure;
+ __le32 rxfrag;
+ __le32 mcastrxframe;
+ __le32 fcserror;
+ __le32 txframe;
+ __le32 wepundecryptable;
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_control {
+ struct cmd_header hdr;
+ __le16 action;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_multicast_adr {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 nr_of_adrs;
+ u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_authenticate {
+ struct cmd_header hdr;
+
+ u8 bssid[ETH_ALEN];
+ u8 authtype;
+ u8 reserved[10];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_deauthenticate {
+ struct cmd_header hdr;
+
+ u8 macaddr[ETH_ALEN];
+ __le16 reasoncode;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_associate {
+ struct cmd_header hdr;
+
+ u8 bssid[6];
+ __le16 capability;
+ __le16 listeninterval;
+ __le16 bcnperiod;
+ u8 dtimperiod;
+ u8 iebuf[512]; /* Enough for required and most optional IEs */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_associate_response {
+ struct cmd_header hdr;
+
+ __le16 capability;
+ __le16 statuscode;
+ __le16 aid;
+ u8 iebuf[512];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_set_wep {
+ struct cmd_header hdr;
+
+ /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
+ __le16 action;
+
+ /* key Index selected for Tx */
+ __le16 keyindex;
+
+ /* 40, 128bit or TXWEP */
+ uint8_t keytype[4];
+ uint8_t keymaterial[4][16];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_snmp_mib {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 oid;
+ __le16 bufsize;
+ u8 value[128];
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_reg_access {
+ __le16 action;
+ __le16 offset;
+ __le32 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_bbp_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_ds_rf_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_radio_control {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 control;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_beacon_control {
+ __le16 action;
+ __le16 beacon_enable;
+ __le16 beacon_period;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_sleep_params {
+ struct cmd_header hdr;
+
+ /* ACT_GET/ACT_SET */
+ __le16 action;
+
+ /* Sleep clock error in ppm */
+ __le16 error;
+
+ /* Wakeup offset in usec */
+ __le16 offset;
+
+ /* Clock stabilization time in usec */
+ __le16 stabletime;
+
+ /* control periodic calibration */
+ uint8_t calcontrol;
+
+ /* control the use of external sleep clock */
+ uint8_t externalsleepclk;
+
+ /* reserved field, should be set to zero */
+ __le16 reserved;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rf_channel {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 channel;
+ __le16 rftype; /* unused */
+ __le16 reserved; /* unused */
+ u8 channellist[32]; /* unused */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rssi {
+ /* weighting factor */
+ __le16 N;
+
+ __le16 reserved_0;
+ __le16 reserved_1;
+ __le16 reserved_2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rssi_rsp {
+ __le16 SNR;
+ __le16 noisefloor;
+ __le16 avgSNR;
+ __le16 avgnoisefloor;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_mac_address {
+ struct cmd_header hdr;
+
+ __le16 action;
+ u8 macadd[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rf_tx_power {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 curlevel;
+ s8 maxlevel;
+ s8 minlevel;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_monitor_mode {
+ __le16 action;
+ __le16 mode;
+} __attribute__ ((packed));
+
+struct cmd_ds_set_boot2_ver {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 version;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_fw_wake_method {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 method;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ps_mode {
+ __le16 action;
+ __le16 nullpktinterval;
+ __le16 multipledtim;
+ __le16 reserved;
+ __le16 locallisteninterval;
+} __attribute__ ((packed));
+
+struct cmd_confirm_sleep {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 nullpktinterval;
+ __le16 multipledtim;
+ __le16 reserved;
+ __le16 locallisteninterval;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_data_rate {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 reserved;
+ u8 rates[MAX_RATES];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 enablehwauto;
+ __le16 bitmap;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_start {
+ struct cmd_header hdr;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 bsstype;
+ __le16 beaconperiod;
+ u8 dtimperiod; /* Reserved on v9 and later */
+ struct ieee_ie_ibss_param_set ibss;
+ u8 reserved1[4];
+ struct ieee_ie_ds_param_set ds;
+ u8 reserved2[4];
+ __le16 probedelay; /* Reserved on v9 and later */
+ __le16 capability;
+ u8 rates[MAX_RATES];
+ u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_result {
+ struct cmd_header hdr;
+
+ u8 pad[3];
+ u8 bssid[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct adhoc_bssdesc {
+ u8 bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 type;
+ __le16 beaconperiod;
+ u8 dtimperiod;
+ __le64 timestamp;
+ __le64 localtime;
+ struct ieee_ie_ds_param_set ds;
+ u8 reserved1[4];
+ struct ieee_ie_ibss_param_set ibss;
+ u8 reserved2[4];
+ __le16 capability;
+ u8 rates[MAX_RATES];
+
+ /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+ * Adhoc join command and will cause a binary layout mismatch with
+ * the firmware
+ */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_join {
+ struct cmd_header hdr;
+
+ struct adhoc_bssdesc bss;
+ __le16 failtimeout; /* Reserved on v9 and later */
+ __le16 probedelay; /* Reserved on v9 and later */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_stop {
+ struct cmd_header hdr;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_enable_rsn {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 enable;
+} __attribute__ ((packed));
+
+struct MrvlIEtype_keyParamSet {
+ /* type ID */
+ __le16 type;
+
+ /* length of Payload */
+ __le16 length;
+
+ /* type of key: WEP=0, TKIP=1, AES=2 */
+ __le16 keytypeid;
+
+ /* key control Info specific to a keytypeid */
+ __le16 keyinfo;
+
+ /* length of key */
+ __le16 keylen;
+
+ /* key material of size keylen */
+ u8 key[32];
+} __attribute__ ((packed));
+
+#define MAX_WOL_RULES 16
+
+struct host_wol_rule {
+ uint8_t rule_no;
+ uint8_t rule_ops;
+ __le16 sig_offset;
+ __le16 sig_length;
+ __le16 reserve;
+ __be32 sig_mask;
+ __be32 signature;
+} __attribute__ ((packed));
+
+struct wol_config {
+ uint8_t action;
+ uint8_t pattern;
+ uint8_t no_rules_in_cmd;
+ uint8_t result;
+ struct host_wol_rule rule[MAX_WOL_RULES];
+} __attribute__ ((packed));
+
+struct cmd_ds_host_sleep {
+ struct cmd_header hdr;
+ __le32 criteria;
+ uint8_t gpio;
+ uint16_t gap;
+ struct wol_config wol_conf;
+} __attribute__ ((packed));
+
+
+
+struct cmd_ds_802_11_key_material {
+ struct cmd_header hdr;
+
+ __le16 action;
+ struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_eeprom_access {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 offset;
+ __le16 len;
+ /* firmware says it returns a maximum of 20 bytes */
+#define LBS_EEPROM_READ_LEN 20
+ u8 value[LBS_EEPROM_READ_LEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_tpc_cfg {
+ struct cmd_header hdr;
+
+ __le16 action;
+ uint8_t enable;
+ int8_t P0;
+ int8_t P1;
+ int8_t P2;
+ uint8_t usesnr;
+} __attribute__ ((packed));
+
+
+struct cmd_ds_802_11_pa_cfg {
+ struct cmd_header hdr;
+
+ __le16 action;
+ uint8_t enable;
+ int8_t P0;
+ int8_t P1;
+ int8_t P2;
+} __attribute__ ((packed));
+
+
+struct cmd_ds_802_11_led_ctrl {
+ __le16 action;
+ __le16 numled;
+ u8 data[256];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_afc {
+ __le16 afc_auto;
+ union {
+ struct {
+ __le16 threshold;
+ __le16 period;
+ };
+ struct {
+ __le16 timing_offset; /* signed */
+ __le16 carrier_offset; /* signed */
+ };
+ };
+} __attribute__ ((packed));
+
+struct cmd_tx_rate_query {
+ __le16 txrate;
+} __attribute__ ((packed));
+
+struct cmd_ds_get_tsf {
+ __le64 tsfvalue;
+} __attribute__ ((packed));
+
+struct cmd_ds_bt_access {
+ __le16 action;
+ __le32 id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_fwt_access {
+ __le16 action;
+ __le32 id;
+ u8 valid;
+ u8 da[ETH_ALEN];
+ u8 dir;
+ u8 ra[ETH_ALEN];
+ __le32 ssn;
+ __le32 dsn;
+ __le32 metric;
+ u8 rate;
+ u8 hopcount;
+ u8 ttl;
+ __le32 expiration;
+ u8 sleepmode;
+ __le32 snr;
+ __le32 references;
+ u8 prec[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_mesh_config {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 channel;
+ __le16 type;
+ __le16 length;
+ u8 data[128]; /* last position reserved */
+} __attribute__ ((packed));
+
+struct cmd_ds_mesh_access {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le32 data[32]; /* last position reserved */
+} __attribute__ ((packed));
+
+/* Number of stats counters returned by the firmware */
+#define MESH_STATS_NUM 8
+
+struct cmd_ds_command {
+ /* command header */
+ __le16 command;
+ __le16 size;
+ __le16 seqnum;
+ __le16 result;
+
+ /* command Body */
+ union {
+ struct cmd_ds_802_11_ps_mode psmode;
+ struct cmd_ds_802_11_monitor_mode monitor;
+ struct cmd_ds_802_11_rssi rssi;
+ struct cmd_ds_802_11_rssi_rsp rssirsp;
+ struct cmd_ds_mac_reg_access macreg;
+ struct cmd_ds_bbp_reg_access bbpreg;
+ struct cmd_ds_rf_reg_access rfreg;
+
+ struct cmd_ds_802_11_tpc_cfg tpccfg;
+ struct cmd_ds_802_11_afc afc;
+ struct cmd_ds_802_11_led_ctrl ledgpio;
+
+ struct cmd_ds_bt_access bt;
+ struct cmd_ds_fwt_access fwt;
+ struct cmd_ds_802_11_beacon_control bcn_ctrl;
+ } params;
+} __attribute__ ((packed));
+
#endif
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
deleted file mode 100644
index c8a1998d474..00000000000
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ /dev/null
@@ -1,800 +0,0 @@
-/*
- * This file contains the function prototypes, data structure
- * and defines for all the host/station commands
- */
-#ifndef _LBS_HOSTCMD_H
-#define _LBS_HOSTCMD_H
-
-#include <linux/wireless.h>
-#include "11d.h"
-#include "types.h"
-
-/* 802.11-related definitions */
-
-/* TxPD descriptor */
-struct txpd {
- /* union to cope up with later FW revisions */
- union {
- /* Current Tx packet status */
- __le32 tx_status;
- struct {
- /* BSS type: client, AP, etc. */
- u8 bss_type;
- /* BSS number */
- u8 bss_num;
- /* Reserved */
- __le16 reserved;
- } bss;
- } u;
- /* Tx control */
- __le32 tx_control;
- __le32 tx_packet_location;
- /* Tx packet length */
- __le16 tx_packet_length;
- /* First 2 byte of destination MAC address */
- u8 tx_dest_addr_high[2];
- /* Last 4 byte of destination MAC address */
- u8 tx_dest_addr_low[4];
- /* Pkt Priority */
- u8 priority;
- /* Pkt Trasnit Power control */
- u8 powermgmt;
- /* Amount of time the packet has been queued in the driver (units = 2ms) */
- u8 pktdelay_2ms;
- /* reserved */
- u8 reserved1;
-} __attribute__ ((packed));
-
-/* RxPD Descriptor */
-struct rxpd {
- /* union to cope up with later FW revisions */
- union {
- /* Current Rx packet status */
- __le16 status;
- struct {
- /* BSS type: client, AP, etc. */
- u8 bss_type;
- /* BSS number */
- u8 bss_num;
- } __attribute__ ((packed)) bss;
- } __attribute__ ((packed)) u;
-
- /* SNR */
- u8 snr;
-
- /* Tx control */
- u8 rx_control;
-
- /* Pkt length */
- __le16 pkt_len;
-
- /* Noise Floor */
- u8 nf;
-
- /* Rx Packet Rate */
- u8 rx_rate;
-
- /* Pkt addr */
- __le32 pkt_ptr;
-
- /* Next Rx RxPD addr */
- __le32 next_rxpd_ptr;
-
- /* Pkt Priority */
- u8 priority;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_header {
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
-} __attribute__ ((packed));
-
-struct cmd_ctrl_node {
- struct list_head list;
- int result;
- /* command response */
- int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
- unsigned long callback_arg;
- /* command data */
- struct cmd_header *cmdbuf;
- /* wait queue */
- u16 cmdwaitqwoken;
- wait_queue_head_t cmdwait_q;
-};
-
-/* Generic structure to hold all key types. */
-struct enc_key {
- u16 len;
- u16 flags; /* KEY_INFO_* from defs.h */
- u16 type; /* KEY_TYPE_* from defs.h */
- u8 key[32];
-};
-
-/* lbs_offset_value */
-struct lbs_offset_value {
- u32 offset;
- u32 value;
-} __attribute__ ((packed));
-
-/* Define general data structure */
-/* cmd_DS_GEN */
-struct cmd_ds_gen {
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
- void *cmdresp[0];
-} __attribute__ ((packed));
-
-#define S_DS_GEN sizeof(struct cmd_ds_gen)
-
-
-/*
- * Define data structure for CMD_GET_HW_SPEC
- * This structure defines the response for the GET_HW_SPEC command
- */
-struct cmd_ds_get_hw_spec {
- struct cmd_header hdr;
-
- /* HW Interface version number */
- __le16 hwifversion;
- /* HW version number */
- __le16 version;
- /* Max number of TxPD FW can handle */
- __le16 nr_txpd;
- /* Max no of Multicast address */
- __le16 nr_mcast_adr;
- /* MAC address */
- u8 permanentaddr[6];
-
- /* region Code */
- __le16 regioncode;
-
- /* Number of antenna used */
- __le16 nr_antenna;
-
- /* FW release number, example 0x01030304 = 2.3.4p1 */
- __le32 fwrelease;
-
- /* Base Address of TxPD queue */
- __le32 wcb_base;
- /* Read Pointer of RxPd queue */
- __le32 rxpd_rdptr;
-
- /* Write Pointer of RxPd queue */
- __le32 rxpd_wrptr;
-
- /*FW/HW capability */
- __le32 fwcapinfo;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_subscribe_event {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 events;
-
- /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
- * number of TLVs. From the v5.1 manual, those TLVs would add up to
- * 40 bytes. However, future firmware might add additional TLVs, so I
- * bump this up a bit.
- */
- uint8_t tlv[128];
-} __attribute__ ((packed));
-
-/*
- * This scan handle Country Information IE(802.11d compliant)
- * Define data structure for CMD_802_11_SCAN
- */
-struct cmd_ds_802_11_scan {
- struct cmd_header hdr;
-
- uint8_t bsstype;
- uint8_t bssid[ETH_ALEN];
- uint8_t tlvbuffer[0];
-#if 0
- mrvlietypes_ssidparamset_t ssidParamSet;
- mrvlietypes_chanlistparamset_t ChanListParamSet;
- mrvlietypes_ratesparamset_t OpRateSet;
-#endif
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_scan_rsp {
- struct cmd_header hdr;
-
- __le16 bssdescriptsize;
- uint8_t nr_sets;
- uint8_t bssdesc_and_tlvbuffer[0];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_get_log {
- struct cmd_header hdr;
-
- __le32 mcasttxframe;
- __le32 failed;
- __le32 retry;
- __le32 multiretry;
- __le32 framedup;
- __le32 rtssuccess;
- __le32 rtsfailure;
- __le32 ackfailure;
- __le32 rxfrag;
- __le32 mcastrxframe;
- __le32 fcserror;
- __le32 txframe;
- __le32 wepundecryptable;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_control {
- struct cmd_header hdr;
- __le16 action;
- u16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_multicast_adr {
- struct cmd_header hdr;
- __le16 action;
- __le16 nr_of_adrs;
- u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
-} __attribute__ ((packed));
-
-struct cmd_ds_gspi_bus_config {
- struct cmd_header hdr;
- __le16 action;
- __le16 bus_delay_mode;
- __le16 host_time_delay_to_read_port;
- __le16 host_time_delay_to_read_register;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_authenticate {
- struct cmd_header hdr;
-
- u8 bssid[ETH_ALEN];
- u8 authtype;
- u8 reserved[10];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_deauthenticate {
- struct cmd_header hdr;
-
- u8 macaddr[ETH_ALEN];
- __le16 reasoncode;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_associate {
- struct cmd_header hdr;
-
- u8 bssid[6];
- __le16 capability;
- __le16 listeninterval;
- __le16 bcnperiod;
- u8 dtimperiod;
- u8 iebuf[512]; /* Enough for required and most optional IEs */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_associate_response {
- struct cmd_header hdr;
-
- __le16 capability;
- __le16 statuscode;
- __le16 aid;
- u8 iebuf[512];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_set_wep {
- struct cmd_header hdr;
-
- /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
- __le16 action;
-
- /* key Index selected for Tx */
- __le16 keyindex;
-
- /* 40, 128bit or TXWEP */
- uint8_t keytype[4];
- uint8_t keymaterial[4][16];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_3_get_stat {
- __le32 xmitok;
- __le32 rcvok;
- __le32 xmiterror;
- __le32 rcverror;
- __le32 rcvnobuffer;
- __le32 rcvcrcerror;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_get_stat {
- __le32 txfragmentcnt;
- __le32 mcasttxframecnt;
- __le32 failedcnt;
- __le32 retrycnt;
- __le32 Multipleretrycnt;
- __le32 rtssuccesscnt;
- __le32 rtsfailurecnt;
- __le32 ackfailurecnt;
- __le32 frameduplicatecnt;
- __le32 rxfragmentcnt;
- __le32 mcastrxframecnt;
- __le32 fcserrorcnt;
- __le32 bcasttxframecnt;
- __le32 bcastrxframecnt;
- __le32 txbeacon;
- __le32 rxbeacon;
- __le32 wepundecryptable;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_snmp_mib {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 oid;
- __le16 bufsize;
- u8 value[128];
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_reg_map {
- __le16 buffersize;
- u8 regmap[128];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_bbp_reg_map {
- __le16 buffersize;
- u8 regmap[128];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_rf_reg_map {
- __le16 buffersize;
- u8 regmap[64];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_reg_access {
- __le16 action;
- __le16 offset;
- __le32 value;
-} __attribute__ ((packed));
-
-struct cmd_ds_bbp_reg_access {
- __le16 action;
- __le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_ds_rf_reg_access {
- __le16 action;
- __le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_radio_control {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 control;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_beacon_control {
- __le16 action;
- __le16 beacon_enable;
- __le16 beacon_period;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_sleep_params {
- struct cmd_header hdr;
-
- /* ACT_GET/ACT_SET */
- __le16 action;
-
- /* Sleep clock error in ppm */
- __le16 error;
-
- /* Wakeup offset in usec */
- __le16 offset;
-
- /* Clock stabilization time in usec */
- __le16 stabletime;
-
- /* control periodic calibration */
- uint8_t calcontrol;
-
- /* control the use of external sleep clock */
- uint8_t externalsleepclk;
-
- /* reserved field, should be set to zero */
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_inactivity_timeout {
- struct cmd_header hdr;
-
- /* ACT_GET/ACT_SET */
- __le16 action;
-
- /* Inactivity timeout in msec */
- __le16 timeout;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_channel {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 channel;
- __le16 rftype; /* unused */
- __le16 reserved; /* unused */
- u8 channellist[32]; /* unused */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rssi {
- /* weighting factor */
- __le16 N;
-
- __le16 reserved_0;
- __le16 reserved_1;
- __le16 reserved_2;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rssi_rsp {
- __le16 SNR;
- __le16 noisefloor;
- __le16 avgSNR;
- __le16 avgnoisefloor;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_mac_address {
- struct cmd_header hdr;
-
- __le16 action;
- u8 macadd[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_tx_power {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 curlevel;
- s8 maxlevel;
- s8 minlevel;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_antenna {
- __le16 action;
-
- /* Number of antennas or 0xffff(diversity) */
- __le16 antennamode;
-
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_monitor_mode {
- __le16 action;
- __le16 mode;
-} __attribute__ ((packed));
-
-struct cmd_ds_set_boot2_ver {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 version;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_fw_wake_method {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 method;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_sleep_period {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 period;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ps_mode {
- __le16 action;
- __le16 nullpktinterval;
- __le16 multipledtim;
- __le16 reserved;
- __le16 locallisteninterval;
-} __attribute__ ((packed));
-
-struct cmd_confirm_sleep {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 nullpktinterval;
- __le16 multipledtim;
- __le16 reserved;
- __le16 locallisteninterval;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_data_rate {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 reserved;
- u8 rates[MAX_RATES];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rate_adapt_rateset {
- struct cmd_header hdr;
- __le16 action;
- __le16 enablehwauto;
- __le16 bitmap;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_start {
- struct cmd_header hdr;
-
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 bsstype;
- __le16 beaconperiod;
- u8 dtimperiod; /* Reserved on v9 and later */
- struct ieee_ie_ibss_param_set ibss;
- u8 reserved1[4];
- struct ieee_ie_ds_param_set ds;
- u8 reserved2[4];
- __le16 probedelay; /* Reserved on v9 and later */
- __le16 capability;
- u8 rates[MAX_RATES];
- u8 tlv_memory_size_pad[100];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_result {
- struct cmd_header hdr;
-
- u8 pad[3];
- u8 bssid[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct adhoc_bssdesc {
- u8 bssid[ETH_ALEN];
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 type;
- __le16 beaconperiod;
- u8 dtimperiod;
- __le64 timestamp;
- __le64 localtime;
- struct ieee_ie_ds_param_set ds;
- u8 reserved1[4];
- struct ieee_ie_ibss_param_set ibss;
- u8 reserved2[4];
- __le16 capability;
- u8 rates[MAX_RATES];
-
- /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
- * Adhoc join command and will cause a binary layout mismatch with
- * the firmware
- */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_join {
- struct cmd_header hdr;
-
- struct adhoc_bssdesc bss;
- __le16 failtimeout; /* Reserved on v9 and later */
- __le16 probedelay; /* Reserved on v9 and later */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_stop {
- struct cmd_header hdr;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_enable_rsn {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 enable;
-} __attribute__ ((packed));
-
-struct MrvlIEtype_keyParamSet {
- /* type ID */
- __le16 type;
-
- /* length of Payload */
- __le16 length;
-
- /* type of key: WEP=0, TKIP=1, AES=2 */
- __le16 keytypeid;
-
- /* key control Info specific to a keytypeid */
- __le16 keyinfo;
-
- /* length of key */
- __le16 keylen;
-
- /* key material of size keylen */
- u8 key[32];
-} __attribute__ ((packed));
-
-#define MAX_WOL_RULES 16
-
-struct host_wol_rule {
- uint8_t rule_no;
- uint8_t rule_ops;
- __le16 sig_offset;
- __le16 sig_length;
- __le16 reserve;
- __be32 sig_mask;
- __be32 signature;
-} __attribute__ ((packed));
-
-struct wol_config {
- uint8_t action;
- uint8_t pattern;
- uint8_t no_rules_in_cmd;
- uint8_t result;
- struct host_wol_rule rule[MAX_WOL_RULES];
-} __attribute__ ((packed));
-
-struct cmd_ds_host_sleep {
- struct cmd_header hdr;
- __le32 criteria;
- uint8_t gpio;
- uint16_t gap;
- struct wol_config wol_conf;
-} __attribute__ ((packed));
-
-
-
-struct cmd_ds_802_11_key_material {
- struct cmd_header hdr;
-
- __le16 action;
- struct MrvlIEtype_keyParamSet keyParamSet[2];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_eeprom_access {
- struct cmd_header hdr;
- __le16 action;
- __le16 offset;
- __le16 len;
- /* firmware says it returns a maximum of 20 bytes */
-#define LBS_EEPROM_READ_LEN 20
- u8 value[LBS_EEPROM_READ_LEN];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_tpc_cfg {
- struct cmd_header hdr;
-
- __le16 action;
- uint8_t enable;
- int8_t P0;
- int8_t P1;
- int8_t P2;
- uint8_t usesnr;
-} __attribute__ ((packed));
-
-
-struct cmd_ds_802_11_pa_cfg {
- struct cmd_header hdr;
-
- __le16 action;
- uint8_t enable;
- int8_t P0;
- int8_t P1;
- int8_t P2;
-} __attribute__ ((packed));
-
-
-struct cmd_ds_802_11_led_ctrl {
- __le16 action;
- __le16 numled;
- u8 data[256];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_afc {
- __le16 afc_auto;
- union {
- struct {
- __le16 threshold;
- __le16 period;
- };
- struct {
- __le16 timing_offset; /* signed */
- __le16 carrier_offset; /* signed */
- };
- };
-} __attribute__ ((packed));
-
-struct cmd_tx_rate_query {
- __le16 txrate;
-} __attribute__ ((packed));
-
-struct cmd_ds_get_tsf {
- __le64 tsfvalue;
-} __attribute__ ((packed));
-
-struct cmd_ds_bt_access {
- __le16 action;
- __le32 id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct cmd_ds_fwt_access {
- __le16 action;
- __le32 id;
- u8 valid;
- u8 da[ETH_ALEN];
- u8 dir;
- u8 ra[ETH_ALEN];
- __le32 ssn;
- __le32 dsn;
- __le32 metric;
- u8 rate;
- u8 hopcount;
- u8 ttl;
- __le32 expiration;
- u8 sleepmode;
- __le32 snr;
- __le32 references;
- u8 prec[ETH_ALEN];
-} __attribute__ ((packed));
-
-
-struct cmd_ds_mesh_config {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 channel;
- __le16 type;
- __le16 length;
- u8 data[128]; /* last position reserved */
-} __attribute__ ((packed));
-
-
-struct cmd_ds_mesh_access {
- struct cmd_header hdr;
-
- __le16 action;
- __le32 data[32]; /* last position reserved */
-} __attribute__ ((packed));
-
-/* Number of stats counters returned by the firmware */
-#define MESH_STATS_NUM 8
-
-struct cmd_ds_command {
- /* command header */
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
-
- /* command Body */
- union {
- struct cmd_ds_802_11_ps_mode psmode;
- struct cmd_ds_802_11_get_stat gstat;
- struct cmd_ds_802_3_get_stat gstat_8023;
- struct cmd_ds_802_11_rf_antenna rant;
- struct cmd_ds_802_11_monitor_mode monitor;
- struct cmd_ds_802_11_rssi rssi;
- struct cmd_ds_802_11_rssi_rsp rssirsp;
- struct cmd_ds_mac_reg_access macreg;
- struct cmd_ds_bbp_reg_access bbpreg;
- struct cmd_ds_rf_reg_access rfreg;
-
- struct cmd_ds_802_11d_domain_info domaininfo;
- struct cmd_ds_802_11d_domain_info domaininforesp;
-
- struct cmd_ds_802_11_tpc_cfg tpccfg;
- struct cmd_ds_802_11_afc afc;
- struct cmd_ds_802_11_led_ctrl ledgpio;
-
- struct cmd_tx_rate_query txrate;
- struct cmd_ds_bt_access bt;
- struct cmd_ds_fwt_access fwt;
- struct cmd_ds_get_tsf gettsf;
- struct cmd_ds_802_11_beacon_control bcn_ctrl;
- } params;
-} __attribute__ ((packed));
-
-#endif
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 62381768f2d..465742f19ec 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -946,6 +946,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_cs_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Now actually get the IRQ */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 485a8d40652..9716728a33c 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -831,6 +831,58 @@ out:
return ret;
}
+static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
+{
+ int ret = -1;
+ struct cmd_header cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ lbs_deb_sdio("send DEEP_SLEEP command\n");
+ ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
+ lbs_cmd_copyback, (unsigned long) &cmd);
+ if (ret)
+ lbs_pr_err("DEEP_SLEEP cmd failed\n");
+
+ mdelay(200);
+ return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+
+}
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
* Ignore the define name, this really means the card has
* successfully received the command.
*/
+ card->priv->is_activity_detected = 1;
if (cause & IF_SDIO_H_INT_DNLD)
lbs_host_to_card_done(card->priv);
@@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func,
priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card;
+ priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+ priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+ priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
priv->fw_ready = 1;
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 60c9b2fcef0..12179c1dc9c 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -51,5 +51,6 @@
#define IF_SDIO_EVENT 0x80fc
#define IF_SDIO_BLOCK_SIZE 256
-
+#define CONFIGURATION_REG 0x03
+#define HOST_POWER_UP (0x1U << 1)
#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 5b3672c4d0c..30d9d0ea28e 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Initialize interrupt handling stuff. */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 3fac4efa5ac..f12d667ba10 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
#ifdef CONFIG_OLPC
if (machine_is_olpc())
priv->reset_card = if_usb_reset_olpc_card;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 87b4e497faa..01f46cf288d 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -14,11 +14,13 @@
#include <linux/stddef.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
+#include "cfg.h"
#include "debugfs.h"
#include "scan.h"
#include "assoc.h"
@@ -43,119 +45,6 @@ module_param_named(libertas_debug, lbs_debug, int, 0644);
struct cmd_confirm_sleep confirm_sleep;
-#define LBS_TX_PWR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
-#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
-
-/* Format { channel, frequency (MHz), maxtxpower } */
-/* band: 'B/G', region: USA FCC/Canada IC */
-static struct chan_freq_power channel_freq_power_US_BG[] = {
- {1, 2412, LBS_TX_PWR_US_DEFAULT},
- {2, 2417, LBS_TX_PWR_US_DEFAULT},
- {3, 2422, LBS_TX_PWR_US_DEFAULT},
- {4, 2427, LBS_TX_PWR_US_DEFAULT},
- {5, 2432, LBS_TX_PWR_US_DEFAULT},
- {6, 2437, LBS_TX_PWR_US_DEFAULT},
- {7, 2442, LBS_TX_PWR_US_DEFAULT},
- {8, 2447, LBS_TX_PWR_US_DEFAULT},
- {9, 2452, LBS_TX_PWR_US_DEFAULT},
- {10, 2457, LBS_TX_PWR_US_DEFAULT},
- {11, 2462, LBS_TX_PWR_US_DEFAULT}
-};
-
-/* band: 'B/G', region: Europe ETSI */
-static struct chan_freq_power channel_freq_power_EU_BG[] = {
- {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
- {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
- {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
- {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
- {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
- {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
- {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
- {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
- {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
- {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
- {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
- {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
- {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
-};
-
-/* band: 'B/G', region: Spain */
-static struct chan_freq_power channel_freq_power_SPN_BG[] = {
- {10, 2457, LBS_TX_PWR_DEFAULT},
- {11, 2462, LBS_TX_PWR_DEFAULT}
-};
-
-/* band: 'B/G', region: France */
-static struct chan_freq_power channel_freq_power_FR_BG[] = {
- {10, 2457, LBS_TX_PWR_FR_DEFAULT},
- {11, 2462, LBS_TX_PWR_FR_DEFAULT},
- {12, 2467, LBS_TX_PWR_FR_DEFAULT},
- {13, 2472, LBS_TX_PWR_FR_DEFAULT}
-};
-
-/* band: 'B/G', region: Japan */
-static struct chan_freq_power channel_freq_power_JPN_BG[] = {
- {1, 2412, LBS_TX_PWR_JP_DEFAULT},
- {2, 2417, LBS_TX_PWR_JP_DEFAULT},
- {3, 2422, LBS_TX_PWR_JP_DEFAULT},
- {4, 2427, LBS_TX_PWR_JP_DEFAULT},
- {5, 2432, LBS_TX_PWR_JP_DEFAULT},
- {6, 2437, LBS_TX_PWR_JP_DEFAULT},
- {7, 2442, LBS_TX_PWR_JP_DEFAULT},
- {8, 2447, LBS_TX_PWR_JP_DEFAULT},
- {9, 2452, LBS_TX_PWR_JP_DEFAULT},
- {10, 2457, LBS_TX_PWR_JP_DEFAULT},
- {11, 2462, LBS_TX_PWR_JP_DEFAULT},
- {12, 2467, LBS_TX_PWR_JP_DEFAULT},
- {13, 2472, LBS_TX_PWR_JP_DEFAULT},
- {14, 2484, LBS_TX_PWR_JP_DEFAULT}
-};
-
-/**
- * the structure for channel, frequency and power
- */
-struct region_cfp_table {
- u8 region;
- struct chan_freq_power *cfp_BG;
- int cfp_no_BG;
-};
-
-/**
- * the structure for the mapping between region and CFP
- */
-static struct region_cfp_table region_cfp_table[] = {
- {0x10, /*US FCC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x20, /*CANADA IC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x30, /*EU*/ channel_freq_power_EU_BG,
- ARRAY_SIZE(channel_freq_power_EU_BG),
- }
- ,
- {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
- ARRAY_SIZE(channel_freq_power_SPN_BG),
- }
- ,
- {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
- ARRAY_SIZE(channel_freq_power_FR_BG),
- }
- ,
- {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
- ARRAY_SIZE(channel_freq_power_JPN_BG),
- }
- ,
-/*Add new region here */
-};
-
/**
* the table to keep region code
*/
@@ -163,13 +52,6 @@ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
- * 802.11b/g supported bitrates (in 500Kb/s units)
- */
-u8 lbs_bg_rates[MAX_RATES] =
- { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0x00, 0x00 };
-
-/**
* FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are
* reserved positions.
@@ -403,7 +285,7 @@ static ssize_t lbs_mesh_set(struct device *dev,
return count;
if (enable)
action = CMD_ACT_MESH_CONFIG_START;
- ret = lbs_mesh_config(priv, action, priv->curbssparams.channel);
+ ret = lbs_mesh_config(priv, action, priv->channel);
if (ret)
return ret;
@@ -574,8 +456,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */
- if (!priv->cur_cmd || priv->tx_pending_len > 0)
- wake_up_interruptible(&priv->waitq);
+ if (!priv->cur_cmd || priv->tx_pending_len > 0) {
+ if (!priv->wakeup_dev_required)
+ wake_up_interruptible(&priv->waitq);
+ }
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -770,7 +654,8 @@ static int lbs_thread(void *data)
shouldsleep = 0; /* We have a command response */
else if (priv->cur_cmd)
shouldsleep = 1; /* Can't send a command; one already running */
- else if (!list_empty(&priv->cmdpendingq))
+ else if (!list_empty(&priv->cmdpendingq) &&
+ !(priv->wakeup_dev_required))
shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
@@ -822,6 +707,26 @@ static int lbs_thread(void *data)
}
spin_unlock_irq(&priv->driver_lock);
+ /* Process hardware events, e.g. card removed, link lost */
+ spin_lock_irq(&priv->driver_lock);
+ while (__kfifo_len(priv->event_fifo)) {
+ u32 event;
+ __kfifo_get(priv->event_fifo, (unsigned char *) &event,
+ sizeof(event));
+ spin_unlock_irq(&priv->driver_lock);
+ lbs_process_event(priv, event);
+ spin_lock_irq(&priv->driver_lock);
+ }
+ spin_unlock_irq(&priv->driver_lock);
+
+ if (priv->wakeup_dev_required) {
+ lbs_deb_thread("Waking up device...\n");
+ /* Wake up device */
+ if (priv->exit_deep_sleep(priv))
+ lbs_deb_thread("Wakeup device failed\n");
+ continue;
+ }
+
/* command timeout stuff */
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
@@ -849,18 +754,7 @@ static int lbs_thread(void *data)
}
priv->cmd_timed_out = 0;
- /* Process hardware events, e.g. card removed, link lost */
- spin_lock_irq(&priv->driver_lock);
- while (__kfifo_len(priv->event_fifo)) {
- u32 event;
- __kfifo_get(priv->event_fifo, (unsigned char *) &event,
- sizeof(event));
- spin_unlock_irq(&priv->driver_lock);
- lbs_process_event(priv, event);
- spin_lock_irq(&priv->driver_lock);
- }
- spin_unlock_irq(&priv->driver_lock);
if (!priv->fw_ready)
continue;
@@ -894,6 +788,9 @@ static int lbs_thread(void *data)
(priv->psstate == PS_STATE_PRE_SLEEP))
continue;
+ if (priv->is_deep_sleep)
+ continue;
+
/* Execute the next command */
if (!priv->dnld_sent && !priv->cur_cmd)
lbs_execute_next_command(priv);
@@ -928,6 +825,7 @@ static int lbs_thread(void *data)
}
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
wake_up_all(&priv->cmd_pending);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -1050,6 +948,62 @@ out:
lbs_deb_leave(LBS_DEB_CMD);
}
+/**
+ * This function put the device back to deep sleep mode when timer expires
+ * and no activity (command, event, data etc.) is detected.
+ */
+static void auto_deepsleep_timer_fn(unsigned long data)
+{
+ struct lbs_private *priv = (struct lbs_private *)data;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (priv->is_activity_detected) {
+ priv->is_activity_detected = 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled &&
+ (!priv->wakeup_dev_required) &&
+ (priv->connect_status != LBS_CONNECTED)) {
+ lbs_deb_main("Entering auto deep sleep mode...\n");
+ ret = lbs_prepare_and_send_command(priv,
+ CMD_802_11_DEEP_SLEEP, 0,
+ 0, 0, NULL);
+ if (ret)
+ lbs_pr_err("Enter Deep Sleep command failed\n");
+ }
+ }
+ mod_timer(&priv->auto_deepsleep_timer , jiffies +
+ (priv->auto_deep_sleep_timeout * HZ)/1000);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 1;
+ if (priv->is_deep_sleep)
+ priv->wakeup_dev_required = 1;
+ mod_timer(&priv->auto_deepsleep_timer ,
+ jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->auto_deep_sleep_timeout = 0;
+ del_timer(&priv->auto_deepsleep_timer);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
static void lbs_sync_channel_worker(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -1092,18 +1046,24 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->mesh_connect_status = LBS_DISCONNECTED;
priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
priv->mode = IW_MODE_INFRA;
- priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+ priv->channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radio_on = 1;
priv->enablehwauto = 1;
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
+ priv->is_deep_sleep = 0;
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->wakeup_dev_required = 0;
+ init_waitqueue_head(&priv->ds_awake_q);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, command_timer_fn,
(unsigned long)priv);
+ setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
+ (unsigned long)priv);
INIT_LIST_HEAD(&priv->cmdfreeq);
INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1142,6 +1102,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
if (priv->event_fifo)
kfifo_free(priv->event_fifo);
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
kfree(priv->networks);
priv->networks = NULL;
@@ -1168,31 +1129,41 @@ static const struct net_device_ops lbs_netdev_ops = {
*/
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
- struct net_device *dev = NULL;
+ struct net_device *dev;
+ struct wireless_dev *wdev;
struct lbs_private *priv = NULL;
lbs_deb_enter(LBS_DEB_MAIN);
/* Allocate an Ethernet device and register it */
- dev = alloc_etherdev(sizeof(struct lbs_private));
- if (!dev) {
- lbs_pr_err("init wlanX device failed\n");
+ wdev = lbs_cfg_alloc(dmdev);
+ if (IS_ERR(wdev)) {
+ lbs_pr_err("cfg80211 init failed\n");
goto done;
}
- priv = netdev_priv(dev);
- dev->ml_priv = priv;
+ /* TODO? */
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ priv = wdev_priv(wdev);
+ priv->wdev = wdev;
if (lbs_init_adapter(priv)) {
lbs_pr_err("failed to initialize adapter structure.\n");
- goto err_init_adapter;
+ goto err_wdev;
}
+ //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
+ dev = alloc_netdev(0, "wlan%d", ether_setup);
+ if (!dev) {
+ dev_err(dmdev, "no memory for network device instance\n");
+ goto err_adapter;
+ }
+
+ dev->ieee80211_ptr = wdev;
+ dev->ml_priv = priv;
+ SET_NETDEV_DEV(dev, dmdev);
+ wdev->netdev = dev;
priv->dev = dev;
- priv->card = card;
- priv->mesh_open = 0;
- priv->infra_open = 0;
- /* Setup the OS Interface to our functions */
dev->netdev_ops = &lbs_netdev_ops;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &lbs_ethtool_ops;
@@ -1201,7 +1172,14 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
#endif
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- SET_NETDEV_DEV(dev, dmdev);
+
+ // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
+
+
+ priv->card = card;
+ priv->mesh_open = 0;
+ priv->infra_open = 0;
+
priv->rtap_net_dev = NULL;
strcpy(dev->name, "wlan%d");
@@ -1211,7 +1189,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
if (IS_ERR(priv->main_thread)) {
lbs_deb_thread("Error creating main thread.\n");
- goto err_init_adapter;
+ goto err_ndev;
}
priv->work_thread = create_singlethread_workqueue("lbs_worker");
@@ -1228,9 +1206,15 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
goto done;
-err_init_adapter:
- lbs_free_adapter(priv);
+ err_ndev:
free_netdev(dev);
+
+ err_adapter:
+ lbs_free_adapter(priv);
+
+ err_wdev:
+ lbs_cfg_free(priv);
+
priv = NULL;
done:
@@ -1243,7 +1227,6 @@ EXPORT_SYMBOL_GPL(lbs_add_card);
void lbs_remove_card(struct lbs_private *priv)
{
struct net_device *dev = priv->dev;
- union iwreq_data wrqu;
lbs_deb_enter(LBS_DEB_MAIN);
@@ -1268,15 +1251,19 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
- memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ lbs_send_disconnect_notification(priv);
+
+ if (priv->is_deep_sleep) {
+ priv->is_deep_sleep = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ }
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);
lbs_free_adapter(priv);
+ lbs_cfg_free(priv);
priv->dev = NULL;
free_netdev(dev);
@@ -1298,11 +1285,8 @@ int lbs_start_card(struct lbs_private *priv)
if (ret)
goto done;
- /* init 802.11d */
- lbs_init_11d(priv);
-
- if (register_netdev(dev)) {
- lbs_pr_err("cannot register ethX device\n");
+ if (lbs_cfg_register(priv)) {
+ lbs_pr_err("cannot register device\n");
goto done;
}
@@ -1327,10 +1311,10 @@ int lbs_start_card(struct lbs_private *priv)
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel)) {
+ priv->channel)) {
priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel))
+ priv->channel))
priv->mesh_tlv = 0;
}
} else if (priv->mesh_fw_ver == MESH_FW_NEW) {
@@ -1339,7 +1323,7 @@ int lbs_start_card(struct lbs_private *priv)
*/
priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel))
+ priv->channel))
priv->mesh_tlv = 0;
}
if (priv->mesh_tlv) {
@@ -1392,6 +1376,7 @@ void lbs_stop_card(struct lbs_private *priv)
/* Delete the timeout of the currently processing command */
del_timer_sync(&priv->command_timer);
+ del_timer_sync(&priv->auto_deepsleep_timer);
/* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags);
@@ -1509,68 +1494,6 @@ static void lbs_remove_mesh(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_MESH);
}
-/**
- * @brief This function finds the CFP in
- * region_cfp_table based on region and band parameter.
- *
- * @param region The region code
- * @param band The band
- * @param cfp_no A pointer to CFP number
- * @return A pointer to CFP
- */
-struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
-{
- int i, end;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- end = ARRAY_SIZE(region_cfp_table);
-
- for (i = 0; i < end ; i++) {
- lbs_deb_main("region_cfp_table[i].region=%d\n",
- region_cfp_table[i].region);
- if (region_cfp_table[i].region == region) {
- *cfp_no = region_cfp_table[i].cfp_no_BG;
- lbs_deb_leave(LBS_DEB_MAIN);
- return region_cfp_table[i].cfp_BG;
- }
- }
-
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
- return NULL;
-}
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
-{
- int ret = 0;
- int i = 0;
-
- struct chan_freq_power *cfp;
- int cfp_no;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- memset(priv->region_channel, 0, sizeof(priv->region_channel));
-
- cfp = lbs_get_region_cfp_table(region, &cfp_no);
- if (cfp != NULL) {
- priv->region_channel[i].nrcfp = cfp_no;
- priv->region_channel[i].CFP = cfp;
- } else {
- lbs_deb_main("wrong region code %#x in band B/G\n",
- region);
- ret = -1;
- goto out;
- }
- priv->region_channel[i].valid = 1;
- priv->region_channel[i].region = region;
- priv->region_channel[i].band = band;
- i++;
-out:
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
-}
-
void lbs_queue_event(struct lbs_private *priv, u32 event)
{
unsigned long flags;
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
index 18fe29faf99..871f914a75f 100644
--- a/drivers/net/wireless/libertas/persistcfg.c
+++ b/drivers/net/wireless/libertas/persistcfg.c
@@ -187,9 +187,9 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
+ if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
lbs_pr_err("inconsistent mesh ID length");
- defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
+ defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
}
/* SSID not null terminated: reserve room for \0 + \n */
@@ -214,7 +214,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
int len;
int ret;
- if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
+ if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
return -EINVAL;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
@@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
/* SSID len */
ie->val.mesh_id_len = len;
/* IE len */
- ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+ ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 65f02cc6752..9f18a19cc49 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -4,7 +4,7 @@
#include <linux/etherdevice.h>
#include <linux/types.h>
-#include "hostcmd.h"
+#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "dev.h"
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 6c95af3023c..c6a6c042b82 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -12,18 +12,19 @@
#include <net/lib80211.h>
#include "host.h"
-#include "decl.h"
#include "dev.h"
#include "scan.h"
+#include "assoc.h"
+#include "wext.h"
#include "cmd.h"
//! Approximate amount of data needed to pass a scan result back to iwlist
#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
- + IW_ESSID_MAX_SIZE \
+ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_UINT_LEN \
+ IW_EV_FREQ_LEN \
+ IW_EV_QUAL_LEN \
- + IW_ESSID_MAX_SIZE \
+ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_PARAM_LEN \
+ 40) /* 40 for WPAIE */
@@ -121,6 +122,189 @@ static inline int is_same_network(struct bss_descriptor *src,
+/*********************************************************************/
+/* */
+/* Region channel support */
+/* */
+/*********************************************************************/
+
+#define LBS_TX_PWR_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
+#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
+
+/* Format { channel, frequency (MHz), maxtxpower } */
+/* band: 'B/G', region: USA FCC/Canada IC */
+static struct chan_freq_power channel_freq_power_US_BG[] = {
+ {1, 2412, LBS_TX_PWR_US_DEFAULT},
+ {2, 2417, LBS_TX_PWR_US_DEFAULT},
+ {3, 2422, LBS_TX_PWR_US_DEFAULT},
+ {4, 2427, LBS_TX_PWR_US_DEFAULT},
+ {5, 2432, LBS_TX_PWR_US_DEFAULT},
+ {6, 2437, LBS_TX_PWR_US_DEFAULT},
+ {7, 2442, LBS_TX_PWR_US_DEFAULT},
+ {8, 2447, LBS_TX_PWR_US_DEFAULT},
+ {9, 2452, LBS_TX_PWR_US_DEFAULT},
+ {10, 2457, LBS_TX_PWR_US_DEFAULT},
+ {11, 2462, LBS_TX_PWR_US_DEFAULT}
+};
+
+/* band: 'B/G', region: Europe ETSI */
+static struct chan_freq_power channel_freq_power_EU_BG[] = {
+ {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
+ {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
+ {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
+ {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
+ {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
+ {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
+ {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
+ {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
+ {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
+ {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
+ {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
+ {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
+ {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
+};
+
+/* band: 'B/G', region: Spain */
+static struct chan_freq_power channel_freq_power_SPN_BG[] = {
+ {10, 2457, LBS_TX_PWR_DEFAULT},
+ {11, 2462, LBS_TX_PWR_DEFAULT}
+};
+
+/* band: 'B/G', region: France */
+static struct chan_freq_power channel_freq_power_FR_BG[] = {
+ {10, 2457, LBS_TX_PWR_FR_DEFAULT},
+ {11, 2462, LBS_TX_PWR_FR_DEFAULT},
+ {12, 2467, LBS_TX_PWR_FR_DEFAULT},
+ {13, 2472, LBS_TX_PWR_FR_DEFAULT}
+};
+
+/* band: 'B/G', region: Japan */
+static struct chan_freq_power channel_freq_power_JPN_BG[] = {
+ {1, 2412, LBS_TX_PWR_JP_DEFAULT},
+ {2, 2417, LBS_TX_PWR_JP_DEFAULT},
+ {3, 2422, LBS_TX_PWR_JP_DEFAULT},
+ {4, 2427, LBS_TX_PWR_JP_DEFAULT},
+ {5, 2432, LBS_TX_PWR_JP_DEFAULT},
+ {6, 2437, LBS_TX_PWR_JP_DEFAULT},
+ {7, 2442, LBS_TX_PWR_JP_DEFAULT},
+ {8, 2447, LBS_TX_PWR_JP_DEFAULT},
+ {9, 2452, LBS_TX_PWR_JP_DEFAULT},
+ {10, 2457, LBS_TX_PWR_JP_DEFAULT},
+ {11, 2462, LBS_TX_PWR_JP_DEFAULT},
+ {12, 2467, LBS_TX_PWR_JP_DEFAULT},
+ {13, 2472, LBS_TX_PWR_JP_DEFAULT},
+ {14, 2484, LBS_TX_PWR_JP_DEFAULT}
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+struct region_cfp_table {
+ u8 region;
+ struct chan_freq_power *cfp_BG;
+ int cfp_no_BG;
+};
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static struct region_cfp_table region_cfp_table[] = {
+ {0x10, /*US FCC */
+ channel_freq_power_US_BG,
+ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x20, /*CANADA IC */
+ channel_freq_power_US_BG,
+ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x30, /*EU*/ channel_freq_power_EU_BG,
+ ARRAY_SIZE(channel_freq_power_EU_BG),
+ }
+ ,
+ {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+ ARRAY_SIZE(channel_freq_power_SPN_BG),
+ }
+ ,
+ {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+ ARRAY_SIZE(channel_freq_power_FR_BG),
+ }
+ ,
+ {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+ ARRAY_SIZE(channel_freq_power_JPN_BG),
+ }
+ ,
+/*Add new region here */
+};
+
+/**
+ * @brief This function finds the CFP in
+ * region_cfp_table based on region and band parameter.
+ *
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ * @return A pointer to CFP
+ */
+static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
+{
+ int i, end;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ end = ARRAY_SIZE(region_cfp_table);
+
+ for (i = 0; i < end ; i++) {
+ lbs_deb_main("region_cfp_table[i].region=%d\n",
+ region_cfp_table[i].region);
+ if (region_cfp_table[i].region == region) {
+ *cfp_no = region_cfp_table[i].cfp_no_BG;
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return region_cfp_table[i].cfp_BG;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
+ return NULL;
+}
+
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
+{
+ int ret = 0;
+ int i = 0;
+
+ struct chan_freq_power *cfp;
+ int cfp_no;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ memset(priv->region_channel, 0, sizeof(priv->region_channel));
+
+ cfp = lbs_get_region_cfp_table(region, &cfp_no);
+ if (cfp != NULL) {
+ priv->region_channel[i].nrcfp = cfp_no;
+ priv->region_channel[i].CFP = cfp;
+ } else {
+ lbs_deb_main("wrong region code %#x in band B/G\n",
+ region);
+ ret = -1;
+ goto out;
+ }
+ priv->region_channel[i].valid = 1;
+ priv->region_channel[i].region = region;
+ priv->region_channel[i].band = band;
+ i++;
+out:
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+
+
+
/*********************************************************************/
/* */
@@ -161,31 +345,15 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv,
scantype = CMD_SCAN_TYPE_ACTIVE;
for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
- if (priv->enable11d && (priv->connect_status != LBS_CONNECTED)
- && (priv->mesh_connect_status != LBS_CONNECTED)) {
- /* Scan all the supported chan for the first scan */
- if (!priv->universal_channel[rgnidx].valid)
- continue;
- scanregion = &priv->universal_channel[rgnidx];
-
- /* clear the parsed_region_chan for the first scan */
- memset(&priv->parsed_region_chan, 0x00,
- sizeof(priv->parsed_region_chan));
- } else {
- if (!priv->region_channel[rgnidx].valid)
- continue;
- scanregion = &priv->region_channel[rgnidx];
- }
+ if (!priv->region_channel[rgnidx].valid)
+ continue;
+ scanregion = &priv->region_channel[rgnidx];
for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
struct chanscanparamset *chan = &scanchanlist[chanidx];
cfp = scanregion->CFP + nextchan;
- if (priv->enable11d)
- scantype = lbs_get_scan_type_11d(cfp->channel,
- &priv->parsed_region_chan);
-
if (scanregion->band == BAND_B || scanregion->band == BAND_G)
chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
@@ -519,7 +687,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
struct ieee_ie_cf_param_set *cf;
struct ieee_ie_ibss_param_set *ibss;
DECLARE_SSID_BUF(ssid);
- struct ieee_ie_country_info_set *pcountryinfo;
uint8_t *pos, *end, *p;
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
uint16_t beaconsize = 0;
@@ -642,26 +809,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
lbs_deb_scan("got IBSS IE\n");
break;
- case WLAN_EID_COUNTRY:
- pcountryinfo = (struct ieee_ie_country_info_set *) pos;
- lbs_deb_scan("got COUNTRY IE\n");
- if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
- || pcountryinfo->header.len > 254) {
- lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
- __func__,
- pcountryinfo->header.len,
- sizeof(pcountryinfo->countrycode));
- ret = -1;
- goto done;
- }
-
- memcpy(&bss->countryinfo, pcountryinfo,
- pcountryinfo->header.len + 2);
- lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
- (uint8_t *) pcountryinfo,
- (int) (pcountryinfo->header.len + 2));
- break;
-
case WLAN_EID_EXT_SUPP_RATES:
/* only process extended supported rate if data rate is
* already found. Data rate IE should come before
@@ -812,7 +959,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
/* SSID */
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
- iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
+ iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
/* Mode */
@@ -1022,9 +1169,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
return -EAGAIN;
/* Update RSSI if current BSS is a locally created ad-hoc BSS */
- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate)
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- CMD_OPTION_WAITFORRSP, 0, NULL);
+ if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
+ err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
+ if (err)
+ goto out;
+ }
mutex_lock(&priv->lock);
list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
@@ -1058,7 +1208,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
dwrq->length = (ev - extra);
dwrq->flags = 0;
-
+out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
return err;
}
@@ -1141,11 +1291,11 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
/* The size of the TLV buffer is equal to the entire command response
* size (scanrespsize) minus the fixed fields (sizeof()'s), the
* BSS Descriptions (bssdescriptsize as bytesLef) and the command
- * response header (S_DS_GEN)
+ * response header (sizeof(struct cmd_header))
*/
tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
+ sizeof(scanresp->nr_sets)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
/*
* Process each scan response returned (scanresp->nr_sets). Save
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index fab7d5d097f..8fb1706d752 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -9,8 +9,36 @@
#include <net/iw_handler.h>
+struct lbs_private;
+
#define MAX_NETWORK_COUNT 128
+/** Chan-freq-TxPower mapping table*/
+struct chan_freq_power {
+ /** channel Number */
+ u16 channel;
+ /** frequency of this channel */
+ u32 freq;
+ /** Max allowed Tx power level */
+ u16 maxtxpower;
+ /** TRUE:channel unsupported; FLASE:supported*/
+ u8 unsupported;
+};
+
+/** region-band mapping table*/
+struct region_channel {
+ /** TRUE if this entry is valid */
+ u8 valid;
+ /** region code for US, Japan ... */
+ u8 region;
+ /** band B/G/A, used for BAND_CONFIG cmd */
+ u8 band;
+ /** Actual No. of elements in the array below */
+ u8 nrcfp;
+ /** chan-freq-txpower mapping table*/
+ struct chan_freq_power *CFP;
+};
+
/**
* @brief Maximum number of channels that can be sent in a setuserscan ioctl
*/
@@ -18,6 +46,8 @@
int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
+
int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
u8 ssid_len);
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 4c018f7a0a8..5d7c011fe29 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -4,7 +4,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include "hostcmd.h"
+#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "defs.h"
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 99905df65b2..3e72c86ceca 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -5,8 +5,8 @@
#define _LBS_TYPES_H_
#include <linux/if_ether.h>
+#include <linux/ieee80211.h>
#include <asm/byteorder.h>
-#include <linux/wireless.h>
struct ieee_ie_header {
u8 id;
@@ -247,7 +247,7 @@ struct mrvl_meshie_val {
uint8_t active_metric_id;
uint8_t mesh_capability;
uint8_t mesh_id_len;
- uint8_t mesh_id[IW_ESSID_MAX_SIZE];
+ uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
} __attribute__ ((packed));
struct mrvl_meshie {
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index be837a0d251..a8eb9e1fcf3 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -45,6 +45,63 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
priv->pending_assoc_req = NULL;
}
+void lbs_send_disconnect_notification(struct lbs_private *priv)
+{
+ union iwreq_data wrqu;
+
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
+{
+ union iwreq_data iwrq;
+ u8 buf[50];
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+ /* Send Event to upper layer */
+ lbs_deb_wext("event indication string %s\n", (char *)buf);
+ lbs_deb_wext("event indication length %d\n", iwrq.data.length);
+ lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
+
+ wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+}
+
+/**
+ * @brief This function handles MIC failure event.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @para event the event id
+ * @return n/a
+ */
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
+{
+ char buf[50];
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ memset(buf, 0, sizeof(buf));
+
+ sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
+
+ if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)
+ strcat(buf, "unicast ");
+ else
+ strcat(buf, "multicast ");
+
+ lbs_send_iwevcustom_event(priv, buf);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
/**
* @brief Find the channel frequency power info with specific channel
@@ -66,8 +123,6 @@ struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j];
- if (priv->enable11d)
- rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP)
continue;
if (rc->band != band)
@@ -107,8 +162,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j];
- if (priv->enable11d)
- rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP)
continue;
if (rc->band != band)
@@ -169,12 +222,12 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
- priv->curbssparams.channel);
+ priv->channel);
if (!cfp) {
- if (priv->curbssparams.channel)
+ if (priv->channel)
lbs_deb_wext("invalid channel %d\n",
- priv->curbssparams.channel);
+ priv->channel);
return -EINVAL;
}
@@ -547,8 +600,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
struct chan_freq_power *cfp;
u8 rates[MAX_RATES + 1];
- u8 flag = 0;
-
lbs_deb_enter(LBS_DEB_WEXT);
dwrq->length = sizeof(struct iw_range);
@@ -570,52 +621,21 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
range->scan_capa = IW_SCAN_CAPA_ESSID;
- if (priv->enable11d &&
- (priv->connect_status == LBS_CONNECTED ||
- priv->mesh_connect_status == LBS_CONNECTED)) {
- u8 chan_no;
- u8 band;
-
- struct parsed_region_chan_11d *parsed_region_chan =
- &priv->parsed_region_chan;
-
- if (parsed_region_chan == NULL) {
- lbs_deb_wext("11d: parsed_region_chan is NULL\n");
- goto out;
- }
- band = parsed_region_chan->band;
- lbs_deb_wext("band %d, nr_char %d\n", band,
- parsed_region_chan->nr_chan);
-
+ for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && (j < ARRAY_SIZE(priv->region_channel)); j++) {
+ cfp = priv->region_channel[j].CFP;
for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && (i < parsed_region_chan->nr_chan); i++) {
- chan_no = parsed_region_chan->chanpwr[i].chan;
- lbs_deb_wext("chan_no %d\n", chan_no);
- range->freq[range->num_frequency].i = (long)chan_no;
+ && priv->region_channel[j].valid
+ && cfp
+ && (i < priv->region_channel[j].nrcfp); i++) {
+ range->freq[range->num_frequency].i =
+ (long)cfp->channel;
range->freq[range->num_frequency].m =
- (long)lbs_chan_2_freq(chan_no) * 100000;
+ (long)cfp->freq * 100000;
range->freq[range->num_frequency].e = 1;
+ cfp++;
range->num_frequency++;
}
- flag = 1;
- }
- if (!flag) {
- for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && (j < ARRAY_SIZE(priv->region_channel)); j++) {
- cfp = priv->region_channel[j].CFP;
- for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && priv->region_channel[j].valid
- && cfp
- && (i < priv->region_channel[j].nrcfp); i++) {
- range->freq[range->num_frequency].i =
- (long)cfp->channel;
- range->freq[range->num_frequency].m =
- (long)cfp->freq * 100000;
- range->freq[range->num_frequency].e = 1;
- cfp++;
- range->num_frequency++;
- }
- }
}
lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
@@ -700,7 +720,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
| IW_ENC_CAPA_CIPHER_CCMP;
}
-out:
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
@@ -709,6 +728,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
struct lbs_private *priv = dev->ml_priv;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -737,8 +757,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
"setting power timeout is not supported\n");
return -EINVAL;
} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- lbs_deb_wext("setting power period not supported\n");
- return -EINVAL;
+ vwrq->value = vwrq->value / 1000;
+ if (!priv->enter_deep_sleep) {
+ lbs_pr_err("deep sleep feature is not implemented "
+ "for this interface driver\n");
+ return -EINVAL;
+ }
+
+ if (priv->connect_status == LBS_CONNECTED) {
+ if ((priv->is_auto_deep_sleep_enabled) &&
+ (vwrq->value == -1000)) {
+ lbs_exit_auto_deep_sleep(priv);
+ return 0;
+ } else {
+ lbs_pr_err("can't use deep sleep cmd in "
+ "connected state\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((vwrq->value < 0) && (vwrq->value != -1000)) {
+ lbs_pr_err("unknown option\n");
+ return -EINVAL;
+ }
+
+ if (vwrq->value > 0) {
+ if (!priv->is_auto_deep_sleep_enabled) {
+ priv->is_activity_detected = 0;
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_enter_auto_deep_sleep(priv);
+ } else {
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_deb_debugfs("auto deep sleep: "
+ "already enabled\n");
+ }
+ return 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled) {
+ lbs_exit_auto_deep_sleep(priv);
+ /* Try to exit deep sleep if auto */
+ /*deep sleep disabled */
+ ret = lbs_set_deep_sleep(priv, 0);
+ }
+ if (vwrq->value == 0)
+ ret = lbs_set_deep_sleep(priv, 1);
+ else if (vwrq->value == -1000)
+ ret = lbs_set_deep_sleep(priv, 0);
+ return ret;
+ }
}
if (priv->psmode != LBS802_11POWERMODECAM) {
@@ -752,6 +818,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
}
lbs_deb_leave(LBS_DEB_WEXT);
+
return 0;
}
@@ -785,7 +852,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
u32 rssi_qual;
u32 tx_qual;
u32 quality = 0;
- int stats_valid = 0;
+ int ret, stats_valid = 0;
u8 rssi;
u32 tx_retries;
struct cmd_ds_802_11_get_log log;
@@ -834,7 +901,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
memset(&log, 0, sizeof(log));
log.hdr.size = cpu_to_le16(sizeof(log));
- lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
+ if (ret)
+ goto out;
tx_retries = le32_to_cpu(log.retry);
@@ -862,8 +931,10 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
stats_valid = 1;
/* update stats asynchronously for future calls */
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL);
+ if (ret)
+ lbs_pr_err("RSSI command failed\n");
out:
if (!stats_valid) {
priv->wstats.miss.beacon = 0;
@@ -973,7 +1044,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
goto out;
}
- if (fwrq->m != priv->curbssparams.channel) {
+ if (fwrq->m != priv->channel) {
lbs_deb_wext("mesh channel change forces eth disconnect\n");
if (priv->mode == IW_MODE_INFRA)
lbs_cmd_80211_deauthenticate(priv,
@@ -1000,6 +1071,7 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
u8 rates[MAX_RATES + 1];
lbs_deb_enter(LBS_DEB_WEXT);
+
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
@@ -1975,7 +2047,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
{
struct lbs_private *priv = dev->ml_priv;
int ret = 0;
- u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len = 0;
struct assoc_request * assoc_req;
int in_ssid_len = dwrq->length;
@@ -1989,7 +2061,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
}
/* Check the size of the string */
- if (in_ssid_len > IW_ESSID_MAX_SIZE) {
+ if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG;
goto out;
}
@@ -2020,7 +2092,7 @@ out:
ret = -ENOMEM;
} else {
/* Copy the SSID to the association request */
- memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = ssid_len;
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
lbs_postpone_association_work(priv);
@@ -2071,7 +2143,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
}
/* Check the size of the string */
- if (dwrq->length > IW_ESSID_MAX_SIZE) {
+ if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG;
goto out;
}
@@ -2086,7 +2158,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
}
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel);
+ priv->channel);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index 4c08db49760..7863baf7d23 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -4,7 +4,15 @@
#ifndef _LBS_WEXT_H_
#define _LBS_WEXT_H_
+void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+
extern struct iw_handler_def lbs_handler_def;
extern struct iw_handler_def mesh_handler_def;
+struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
+ struct lbs_private *priv,
+ u8 band,
+ u16 channel);
+
#endif
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 83b635fd778..dce652054af 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,8 +1,10 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
- depends on CFG80211
+ depends on CFG80211 && CFG80211_WEXT
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
select CRYPTO
select CRYPTO_MICHAEL_MIC
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 359652d35e6..404830f47ab 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -60,8 +60,15 @@ static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
/* Set priv->firmware type, determine firmware properties
* This function can be called before we have registerred with netdev,
* so all errors go out with dev_* rather than printk
+ *
+ * If non-NULL stores a firmware description in fw_name.
+ * If non-NULL stores a HW version in hw_ver
+ *
+ * These are output via generic cfg80211 ethtool support.
*/
-int determine_fw_capabilities(struct orinoco_private *priv)
+int determine_fw_capabilities(struct orinoco_private *priv,
+ char *fw_name, size_t fw_name_len,
+ u32 *hw_ver)
{
struct device *dev = priv->dev;
hermes_t *hw = &priv->hw;
@@ -85,6 +92,12 @@ int determine_fw_capabilities(struct orinoco_private *priv)
dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
+ if (hw_ver)
+ *hw_ver = (((nic_id.id & 0xff) << 24) |
+ ((nic_id.variant & 0xff) << 16) |
+ ((nic_id.major & 0xff) << 8) |
+ (nic_id.minor & 0xff));
+
priv->firmware_type = determine_firmware_type(&nic_id);
/* Get the firmware version */
@@ -135,8 +148,9 @@ int determine_fw_capabilities(struct orinoco_private *priv)
case FIRMWARE_TYPE_AGERE:
/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+ if (fw_name)
+ snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d",
+ sta_id.major, sta_id.minor);
firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
@@ -185,8 +199,8 @@ int determine_fw_capabilities(struct orinoco_private *priv)
tmp[SYMBOL_MAX_VER_LEN] = '\0';
}
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Symbol %s", tmp);
+ if (fw_name)
+ snprintf(fw_name, fw_name_len, "Symbol %s", tmp);
priv->has_ibss = (firmver >= 0x20000);
priv->has_wep = (firmver >= 0x15012);
@@ -224,9 +238,9 @@ int determine_fw_capabilities(struct orinoco_private *priv)
* different and less well tested */
/* D-Link MAC : 00:40:05:* */
/* Addtron MAC : 00:90:D1:* */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
- sta_id.variant);
+ if (fw_name)
+ snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d",
+ sta_id.major, sta_id.minor, sta_id.variant);
firmver = ((unsigned long)sta_id.major << 16) |
((unsigned long)sta_id.minor << 8) | sta_id.variant;
@@ -245,7 +259,8 @@ int determine_fw_capabilities(struct orinoco_private *priv)
}
break;
}
- dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
+ if (fw_name)
+ dev_info(dev, "Firmware determined as %s\n", fw_name);
return 0;
}
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
index 8df6e8752be..e2f7fdc4d45 100644
--- a/drivers/net/wireless/orinoco/hw.h
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -24,7 +24,8 @@
struct orinoco_private;
struct dev_addr_list;
-int determine_fw_capabilities(struct orinoco_private *priv);
+int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name,
+ size_t fw_name_len, u32 *hw_ver);
int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
int orinoco_hw_allocate_fid(struct orinoco_private *priv);
int orinoco_get_bitratemode(int bitrate, int automatic);
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 7a32bcb0c03..753a1804eee 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -83,7 +83,6 @@
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
#include <linux/suspend.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
@@ -162,8 +161,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
| HERMES_EV_WTERR | HERMES_EV_INFO \
| HERMES_EV_INFDROP)
-static const struct ethtool_ops orinoco_ethtool_ops;
-
/********************************************************************/
/* Data types */
/********************************************************************/
@@ -1994,7 +1991,9 @@ int orinoco_init(struct orinoco_private *priv)
goto out;
}
- err = determine_fw_capabilities(priv);
+ err = determine_fw_capabilities(priv, wiphy->fw_version,
+ sizeof(wiphy->fw_version),
+ &wiphy->hw_version);
if (err != 0) {
dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
@@ -2010,7 +2009,9 @@ int orinoco_init(struct orinoco_private *priv)
priv->do_fw_download = 0;
/* Check firmware version again */
- err = determine_fw_capabilities(priv);
+ err = determine_fw_capabilities(priv, wiphy->fw_version,
+ sizeof(wiphy->fw_version),
+ &wiphy->hw_version);
if (err != 0) {
dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
@@ -2212,7 +2213,6 @@ int orinoco_if_add(struct orinoco_private *priv,
dev->ieee80211_ptr = wdev;
dev->netdev_ops = &orinoco_netdev_ops;
dev->watchdog_timeo = HZ; /* 1 second timeout */
- dev->ethtool_ops = &orinoco_ethtool_ops;
dev->wireless_handlers = &orinoco_handler_def;
#ifdef WIRELESS_SPY
dev->wireless_data = &priv->wireless_data;
@@ -2225,6 +2225,7 @@ int orinoco_if_add(struct orinoco_private *priv,
netif_carrier_off(dev);
memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+ memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
dev->base_addr = base_addr;
dev->irq = irq;
@@ -2348,27 +2349,6 @@ void orinoco_down(struct orinoco_private *priv)
}
EXPORT_SYMBOL(orinoco_down);
-static void orinoco_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
- strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
- strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
- if (dev->dev.parent)
- strncpy(info->bus_info, dev_name(dev->dev.parent),
- sizeof(info->bus_info) - 1);
- else
- snprintf(info->bus_info, sizeof(info->bus_info) - 1,
- "PCMCIA %p", priv->hw.iobase);
-}
-
-static const struct ethtool_ops orinoco_ethtool_ops = {
- .get_drvinfo = orinoco_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-
/********************************************************************/
/* Module initialization */
/********************************************************************/
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 9ac6f1dda4b..665ef56f838 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -93,7 +93,6 @@ struct orinoco_private {
/* Capabilities of the hardware/firmware */
fwtype_t firmware_type;
- char fw_name[32];
int ibss_port;
int nicbuf_size;
u16 channel_mask;
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index ed1f997e352..390c0c7b3ac 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -53,6 +53,32 @@ config RT61PCI
When compiled as a module, this driver will be called rt61pci.
+config RT2800PCI_PCI
+ tristate
+ depends on PCI
+ default y
+
+config RT2800PCI_SOC
+ tristate
+ depends on RALINK_RT288X || RALINK_RT305X
+ default y
+
+config RT2800PCI
+ tristate "Ralink rt2800 (PCI/PCMCIA) support"
+ depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL
+ select RT2X00_LIB_PCI if RT2800PCI_PCI
+ select RT2X00_LIB_SOC if RT2800PCI_SOC
+ select RT2X00_LIB_HT
+ select RT2X00_LIB_FIRMWARE
+ select RT2X00_LIB_CRYPTO
+ select CRC_CCITT
+ select EEPROM_93CX6
+ ---help---
+ This adds support for rt2800 wireless chipset family.
+ Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052
+
+ When compiled as a module, this driver will be called "rt2800pci.ko".
+
config RT2500USB
tristate "Ralink rt2500 (USB) support"
depends on USB
@@ -95,6 +121,10 @@ config RT2X00_LIB_PCI
tristate
select RT2X00_LIB
+config RT2X00_LIB_SOC
+ tristate
+ select RT2X00_LIB
+
config RT2X00_LIB_USB
tristate
select RT2X00_LIB
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 13043ea9766..912f5f67e15 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -11,10 +11,12 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
+obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
obj-$(CONFIG_RT2400PCI) += rt2400pci.o
obj-$(CONFIG_RT2500PCI) += rt2500pci.o
obj-$(CONFIG_RT61PCI) += rt61pci.o
+obj-$(CONFIG_RT2800PCI) += rt2800pci.o
obj-$(CONFIG_RT2500USB) += rt2500usb.o
obj-$(CONFIG_RT73USB) += rt73usb.o
obj-$(CONFIG_RT2800USB) += rt2800usb.o
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
new file mode 100644
index 00000000000..be81788b80c
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -0,0 +1,3323 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2800pci
+ Abstract: rt2800pci device specific routines.
+ Supported chipsets: RT2800E & RT2800ED.
+ */
+
+#include <linux/crc-ccitt.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2x00soc.h"
+#include "rt2800pci.h"
+
+#ifdef CONFIG_RT2800PCI_PCI_MODULE
+#define CONFIG_RT2800PCI_PCI
+#endif
+
+#ifdef CONFIG_RT2800PCI_WISOC_MODULE
+#define CONFIG_RT2800PCI_WISOC
+#endif
+
+/*
+ * Allow hardware encryption to be disabled.
+ */
+static int modparam_nohwcrypt = 1;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+/*
+ * Register access.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg))
+#define WAIT_FOR_RFCSR(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg))
+#define WAIT_FOR_MCU(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
+ H2M_MAILBOX_CSR_OWNER, (__reg))
+
+static void rt2800pci_bbp_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_VALUE, value);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_bbp_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
+ */
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg);
+
+ WAIT_FOR_BBP(rt2x00dev, &reg);
+ }
+
+ *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE);
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_rfcsr_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the RFCSR becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RF_CSR_CFG_DATA, value);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 1);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_rfcsr_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the RFCSR becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
+ */
+ if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 0);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg);
+
+ WAIT_FOR_RFCSR(rt2x00dev, &reg);
+ }
+
+ *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA);
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_REG_VALUE_BW, value);
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_STANDBYMODE, 0);
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_SEL, 0);
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG0, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev,
+ const u8 command, const u8 token,
+ const u8 arg0, const u8 arg1)
+{
+ u32 reg;
+
+ /*
+ * RT2880 and RT3052 don't support MCU requests.
+ */
+ if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
+ rt2x00_rt(&rt2x00dev->chip, RT3052))
+ return;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the MCU becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+
+ reg = 0;
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
+{
+ unsigned int i;
+ u32 reg;
+
+ for (i = 0; i < 200; i++) {
+ rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
+
+ if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) ||
+ (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) ||
+ (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD2) == token) ||
+ (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD3) == token))
+ break;
+
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ if (i == 200)
+ ERROR(rt2x00dev, "MCU request failed, no response from hardware\n");
+
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+}
+
+#ifdef CONFIG_RT2800PCI_WISOC
+static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+{
+ u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
+
+ memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
+}
+#else
+static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2800PCI_WISOC */
+
+#ifdef CONFIG_RT2800PCI_PCI
+static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT);
+}
+
+static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
+}
+
+static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt2800pci_eepromregister_read;
+ eeprom.register_write = rt2800pci_eepromregister_write;
+ eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+}
+
+static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev,
+ unsigned int i)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, EFUSE_CTRL, &reg);
+ rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, i);
+ rt2x00_set_field32(&reg, EFUSE_CTRL_MODE, 0);
+ rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
+ rt2x00pci_register_write(rt2x00dev, EFUSE_CTRL, reg);
+
+ /* Wait until the EEPROM has been loaded */
+ rt2x00pci_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
+
+ /* Apparently the data is read from end to start */
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA3,
+ (u32 *)&rt2x00dev->eeprom[i]);
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA2,
+ (u32 *)&rt2x00dev->eeprom[i + 2]);
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA1,
+ (u32 *)&rt2x00dev->eeprom[i + 4]);
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA0,
+ (u32 *)&rt2x00dev->eeprom[i + 6]);
+}
+
+static void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+
+ for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
+ rt2800pci_efuse_read(rt2x00dev, i);
+}
+#else
+static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2800PCI_PCI */
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+static const struct rt2x00debug rt2800pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2x00pci_register_read,
+ .write = rt2x00pci_register_write,
+ .flags = RT2X00DEBUGFS_OFFSET,
+ .word_base = CSR_REG_BASE,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_base = EEPROM_BASE,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2800pci_bbp_read,
+ .write = rt2800pci_bbp_write,
+ .word_base = BBP_BASE,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2800pci_rf_write,
+ .word_base = RF_BASE,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+static int rt2800pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
+ return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
+}
+
+#ifdef CONFIG_RT2X00_LIB_LEDS
+static void rt2800pci_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ unsigned int enabled = brightness != LED_OFF;
+ unsigned int bg_mode =
+ (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ);
+ unsigned int polarity =
+ rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
+ EEPROM_FREQ_LED_POLARITY);
+ unsigned int ledmode =
+ rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
+ EEPROM_FREQ_LED_MODE);
+
+ if (led->type == LED_TYPE_RADIO) {
+ rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+ enabled ? 0x20 : 0);
+ } else if (led->type == LED_TYPE_ASSOC) {
+ rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+ enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
+ } else if (led->type == LED_TYPE_QUALITY) {
+ /*
+ * The brightness is divided into 6 levels (0 - 5),
+ * The specs tell us the following levels:
+ * 0, 1 ,3, 7, 15, 31
+ * to determine the level in a simple way we can simply
+ * work with bitshifting:
+ * (1 << level) - 1
+ */
+ rt2800pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
+ (1 << brightness / (LED_FULL / 6)) - 1,
+ polarity);
+ }
+}
+
+static int rt2800pci_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ u32 reg;
+
+ rt2x00pci_register_read(led->rt2x00dev, LED_CFG, &reg);
+ rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, *delay_on);
+ rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, *delay_off);
+ rt2x00_set_field32(&reg, LED_CFG_SLOW_BLINK_PERIOD, 3);
+ rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, 3);
+ rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, 12);
+ rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE, 3);
+ rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, 1);
+ rt2x00pci_register_write(led->rt2x00dev, LED_CFG, reg);
+
+ return 0;
+}
+
+static void rt2800pci_init_led(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_led *led,
+ enum led_type type)
+{
+ led->rt2x00dev = rt2x00dev;
+ led->type = type;
+ led->led_dev.brightness_set = rt2800pci_brightness_set;
+ led->led_dev.blink_set = rt2800pci_blink_set;
+ led->flags = LED_INITIALIZED;
+}
+#endif /* CONFIG_RT2X00_LIB_LEDS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct mac_wcid_entry wcid_entry;
+ struct mac_iveiv_entry iveiv_entry;
+ u32 offset;
+ u32 reg;
+
+ offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
+ !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
+ (crypto->cmd == SET_KEY) * crypto->cipher);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
+ (crypto->cmd == SET_KEY) * crypto->bssidx);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
+
+ memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+ if ((crypto->cipher == CIPHER_TKIP) ||
+ (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
+ (crypto->cipher == CIPHER_AES))
+ iveiv_entry.iv[3] |= 0x20;
+ iveiv_entry.iv[3] |= key->keyidx << 6;
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
+
+ offset = MAC_WCID_ENTRY(key->hw_key_idx);
+
+ memset(&wcid_entry, 0, sizeof(wcid_entry));
+ if (crypto->cmd == SET_KEY)
+ memcpy(&wcid_entry, crypto->address, ETH_ALEN);
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &wcid_entry, sizeof(wcid_entry));
+}
+
+static int rt2800pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_key_entry key_entry;
+ struct rt2x00_field32 field;
+ u32 offset;
+ u32 reg;
+
+ if (crypto->cmd == SET_KEY) {
+ key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx;
+
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ offset = SHARED_KEY_ENTRY(key->hw_key_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &key_entry, sizeof(key_entry));
+ }
+
+ /*
+ * The cipher types are stored over multiple registers
+ * starting with SHARED_KEY_MODE_BASE each word will have
+ * 32 bits and contains the cipher types for 2 bssidx each.
+ * Using the correct defines correctly will cause overhead,
+ * so just calculate the correct offset.
+ */
+ field.bit_offset = 4 * (key->hw_key_idx % 8);
+ field.bit_mask = 0x7 << field.bit_offset;
+
+ offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8);
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, field,
+ (crypto->cmd == SET_KEY) * crypto->cipher);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ /*
+ * Update WCID information
+ */
+ rt2800pci_config_wcid_attr(rt2x00dev, crypto, key);
+
+ return 0;
+}
+
+static int rt2800pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_key_entry key_entry;
+ u32 offset;
+
+ if (crypto->cmd == SET_KEY) {
+ /*
+ * 1 pairwise key is possible per AID, this means that the AID
+ * equals our hw_key_idx. Make sure the WCID starts _after_ the
+ * last possible shared key entry.
+ */
+ if (crypto->aid > (256 - 32))
+ return -ENOSPC;
+
+ key->hw_key_idx = 32 + crypto->aid;
+
+
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &key_entry, sizeof(key_entry));
+ }
+
+ /*
+ * Update WCID information
+ */
+ rt2800pci_config_wcid_attr(rt2x00dev, crypto, key);
+
+ return 0;
+}
+
+static void rt2800pci_config_filter(struct rt2x00_dev *rt2x00dev,
+ const unsigned int filter_flags)
+{
+ u32 reg;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_FILTER_CFG, &reg);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CRC_ERROR,
+ !(filter_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
+ !(filter_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
+ !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
+ !(filter_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BROADCAST, 0);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_DUPLICATE, 1);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CF_END_ACK,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CF_END,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_ACK,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CTS,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_RTS,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
+ !(filter_flags & FIF_PSPOLL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00pci_register_write(rt2x00dev, RX_FILTER_CFG, reg);
+}
+
+static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags)
+{
+ unsigned int beacon_base;
+ u32 reg;
+
+ if (flags & CONFIG_UPDATE_TYPE) {
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
+ rt2x00pci_register_write(rt2x00dev, beacon_base, 0);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ }
+
+ if (flags & CONFIG_UPDATE_MAC) {
+ reg = le32_to_cpu(conf->mac[1]);
+ rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
+ conf->mac[1] = cpu_to_le32(reg);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_ADDR_DW0,
+ conf->mac, sizeof(conf->mac));
+ }
+
+ if (flags & CONFIG_UPDATE_BSSID) {
+ reg = le32_to_cpu(conf->bssid[1]);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 0);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
+ conf->bssid[1] = cpu_to_le32(reg);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
+ conf->bssid, sizeof(conf->bssid));
+ }
+}
+
+static void rt2800pci_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20);
+ rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY,
+ !!erp->short_preamble);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_AR_PREAMBLE,
+ !!erp->short_preamble);
+ rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL,
+ erp->cts_protection ? 2 : 0);
+ rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE,
+ erp->basic_rates);
+ rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+
+ rt2x00pci_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time);
+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
+ rt2x00pci_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
+ erp->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+}
+
+static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant)
+{
+ u8 r1;
+ u8 r3;
+
+ rt2800pci_bbp_read(rt2x00dev, 1, &r1);
+ rt2800pci_bbp_read(rt2x00dev, 3, &r3);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch ((int)ant->tx) {
+ case 1:
+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
+ break;
+ case 2:
+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
+ break;
+ case 3:
+ /* Do nothing */
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch ((int)ant->rx) {
+ case 1:
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
+ break;
+ case 2:
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1);
+ break;
+ case 3:
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2);
+ break;
+ }
+
+ rt2800pci_bbp_write(rt2x00dev, 3, r3);
+ rt2800pci_bbp_write(rt2x00dev, 1, r1);
+}
+
+static void rt2800pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u16 eeprom;
+ short lna_gain;
+
+ if (libconf->rf.channel <= 14) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG);
+ } else if (libconf->rf.channel <= 64) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0);
+ } else if (libconf->rf.channel <= 128) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1);
+ } else {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2);
+ }
+
+ rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt2800pci_config_channel_rt2x(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ if (rt2x00dev->default_ant.tx == 1)
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1);
+
+ if (rt2x00dev->default_ant.rx == 1) {
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1);
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
+ } else if (rt2x00dev->default_ant.rx == 2)
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
+
+ if (rf->channel > 14) {
+ /*
+ * When TX power is below 0, we should increase it by 7 to
+ * make it a positive value (Minumum value is -7).
+ * However this means that values between 0 and 7 have
+ * double meaning, and we should set a 7DBm boost flag.
+ */
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST,
+ (info->tx_power1 >= 0));
+
+ if (info->tx_power1 < 0)
+ info->tx_power1 += 7;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A,
+ TXPOWER_A_TO_DEV(info->tx_power1));
+
+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST,
+ (info->tx_power2 >= 0));
+
+ if (info->tx_power2 < 0)
+ info->tx_power2 += 7;
+
+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A,
+ TXPOWER_A_TO_DEV(info->tx_power2));
+ } else {
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G,
+ TXPOWER_G_TO_DEV(info->tx_power1));
+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G,
+ TXPOWER_G_TO_DEV(info->tx_power2));
+ }
+
+ rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf));
+
+ rt2800pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt2800pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt2800pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt2800pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt2800pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt2800pci_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2800pci_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ u8 rfcsr;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf1);
+ rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf3);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 6, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2);
+ rt2800pci_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 12, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
+ TXPOWER_G_TO_DEV(info->tx_power1));
+ rt2800pci_rfcsr_write(rt2x00dev, 12, rfcsr);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
+ rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr);
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24,
+ rt2x00dev->calibration[conf_is_ht40(conf)]);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
+ rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr);
+}
+
+static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ u32 reg;
+ unsigned int tx_pin;
+ u8 bbp;
+
+ if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
+ rt2800pci_config_channel_rt2x(rt2x00dev, conf, rf, info);
+ else
+ rt2800pci_config_channel_rt3x(rt2x00dev, conf, rf, info);
+
+ /*
+ * Change BBP settings
+ */
+ rt2800pci_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+ rt2800pci_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+ rt2800pci_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
+ rt2800pci_bbp_write(rt2x00dev, 86, 0);
+
+ if (rf->channel <= 14) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ rt2800pci_bbp_write(rt2x00dev, 82, 0x62);
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x46);
+ } else {
+ rt2800pci_bbp_write(rt2x00dev, 82, 0x84);
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x50);
+ }
+ } else {
+ rt2800pci_bbp_write(rt2x00dev, 82, 0xf2);
+
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x46);
+ else
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x50);
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf));
+ rt2x00_set_field32(&reg, TX_BAND_CFG_A, rf->channel > 14);
+ rt2x00_set_field32(&reg, TX_BAND_CFG_BG, rf->channel <= 14);
+ rt2x00pci_register_write(rt2x00dev, TX_BAND_CFG, reg);
+
+ tx_pin = 0;
+
+ /* Turn on unused PA or LNA when not using 1T or 1R */
+ if (rt2x00dev->default_ant.tx != 1) {
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
+ }
+
+ /* Turn on unused PA or LNA when not using 1T or 1R */
+ if (rt2x00dev->default_ant.rx != 1) {
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
+ }
+
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14);
+
+ rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
+
+ rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
+ rt2800pci_bbp_write(rt2x00dev, 4, bbp);
+
+ rt2800pci_bbp_read(rt2x00dev, 3, &bbp);
+ rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
+ rt2800pci_bbp_write(rt2x00dev, 3, bbp);
+
+ if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+ if (conf_is_ht40(conf)) {
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x1a);
+ rt2800pci_bbp_write(rt2x00dev, 70, 0x0a);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x16);
+ } else {
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x16);
+ rt2800pci_bbp_write(rt2x00dev, 70, 0x08);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x11);
+ }
+ }
+
+ msleep(1);
+}
+
+static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ u32 reg;
+ u32 value = TXPOWER_G_TO_DEV(txpower);
+ u8 r1;
+
+ rt2800pci_bbp_read(rt2x00dev, 1, &r1);
+ rt2x00_set_field8(&reg, BBP1_TX_POWER, 0);
+ rt2800pci_bbp_write(rt2x00dev, 1, r1);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_0, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_1MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_2MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_55MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_11MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_6MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_9MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_12MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_18MBS, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_1, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_24MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_36MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_48MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_54MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS0, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS1, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS2, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS3, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_2, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS4, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS5, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS6, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS7, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS8, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS9, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS10, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS11, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_3, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS12, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS13, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS14, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS15, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN1, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN2, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN3, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN4, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_4, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN5, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN6, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN7, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN8, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_4, reg);
+}
+
+static void rt2800pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TX_RTY_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_SHORT_RTY_LIMIT,
+ libconf->conf->short_frame_max_tx_count);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT,
+ libconf->conf->long_frame_max_tx_count);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_THRE, 2000);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_NON_AGG_RTY_MODE, 0);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_AGG_RTY_MODE, 0);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_RTY_CFG, reg);
+}
+
+static void rt2800pci_config_ps(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ enum dev_state state =
+ (libconf->conf->flags & IEEE80211_CONF_PS) ?
+ STATE_SLEEP : STATE_AWAKE;
+ u32 reg;
+
+ if (state == STATE_SLEEP) {
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0);
+
+ rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE,
+ libconf->conf->listen_interval - 1);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 1);
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
+
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
+ } else {
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
+
+ rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 0);
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
+ }
+}
+
+static void rt2800pci_config(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags)
+{
+ /* Always recalculate LNA gain before changing configuration */
+ rt2800pci_config_lna_gain(rt2x00dev, libconf);
+
+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
+ rt2800pci_config_channel(rt2x00dev, libconf->conf,
+ &libconf->rf, &libconf->channel);
+ if (flags & IEEE80211_CONF_CHANGE_POWER)
+ rt2800pci_config_txpower(rt2x00dev, libconf->conf->power_level);
+ if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ rt2800pci_config_retry_limit(rt2x00dev, libconf);
+ if (flags & IEEE80211_CONF_CHANGE_PS)
+ rt2800pci_config_ps(rt2x00dev, libconf);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2800pci_link_stats(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, &reg);
+ qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR);
+}
+
+static u8 rt2800pci_get_default_vgc(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)
+ return 0x2e + rt2x00dev->lna_gain;
+
+ if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
+ return 0x32 + (rt2x00dev->lna_gain * 5) / 3;
+ else
+ return 0x3a + (rt2x00dev->lna_gain * 5) / 3;
+}
+
+static inline void rt2800pci_set_vgc(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, u8 vgc_level)
+{
+ if (qual->vgc_level != vgc_level) {
+ rt2800pci_bbp_write(rt2x00dev, 66, vgc_level);
+ qual->vgc_level = vgc_level;
+ qual->vgc_level_reg = vgc_level;
+ }
+}
+
+static void rt2800pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
+{
+ rt2800pci_set_vgc(rt2x00dev, qual,
+ rt2800pci_get_default_vgc(rt2x00dev));
+}
+
+static void rt2800pci_link_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, const u32 count)
+{
+ if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION)
+ return;
+
+ /*
+ * When RSSI is better then -80 increase VGC level with 0x10
+ */
+ rt2800pci_set_vgc(rt2x00dev, qual,
+ rt2800pci_get_default_vgc(rt2x00dev) +
+ ((qual->rssi > -80) * 0x10));
+}
+
+/*
+ * Firmware functions
+ */
+static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+ return FIRMWARE_RT2860;
+}
+
+static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len)
+{
+ u16 fw_crc;
+ u16 crc;
+
+ /*
+ * Only support 8kb firmware files.
+ */
+ if (len != 8192)
+ return FW_BAD_LENGTH;
+
+ /*
+ * The last 2 bytes in the firmware array are the crc checksum itself,
+ * this means that we should never pass those 2 bytes to the crc
+ * algorithm.
+ */
+ fw_crc = (data[len - 2] << 8 | data[len - 1]);
+
+ /*
+ * Use the crc ccitt algorithm.
+ * This will return the same value as the legacy driver which
+ * used bit ordering reversion on the both the firmware bytes
+ * before input input as well as on the final output.
+ * Obviously using crc ccitt directly is much more efficient.
+ */
+ crc = crc_ccitt(~0, data, len - 2);
+
+ /*
+ * There is a small difference between the crc-itu-t + bitrev and
+ * the crc-ccitt crc calculation. In the latter method the 2 bytes
+ * will be swapped, use swab16 to convert the crc to the correct
+ * value.
+ */
+ crc = swab16(crc);
+
+ return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
+}
+
+static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len)
+{
+ unsigned int i;
+ u32 reg;
+
+ /*
+ * Wait for stable hardware.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg && reg != ~0)
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
+
+ /*
+ * Disable DMA, will be reenabled later when enabling
+ * the radio.
+ */
+ rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ /*
+ * enable Host program ram write selection
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PBF_SYS_CTRL_HOST_RAM_WRITE, 1);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
+
+ /*
+ * Write firmware to device.
+ */
+ rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data, len);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
+
+ /*
+ * Wait for device to stabilize.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+ if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "PBF system register not ready.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Disable interrupts
+ */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF);
+
+ /*
+ * Initialize BBP R/W access agent
+ */
+ rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+
+ return 0;
+}
+
+/*
+ * Initialization functions.
+ */
+static bool rt2800pci_get_entry_state(struct queue_entry *entry)
+{
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ u32 word;
+
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+
+ return (!rt2x00_get_field32(word, RXD_W1_DMA_DONE));
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+
+ return (!rt2x00_get_field32(word, TXD_W1_DMA_DONE));
+ }
+}
+
+static void rt2800pci_clear_entry(struct queue_entry *entry)
+{
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ u32 word;
+
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_SDP0, skbdesc->skb_dma);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+ }
+}
+
+static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct queue_entry_priv_pci *entry_priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
+ /*
+ * Initialize registers.
+ */
+ entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0);
+
+ entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0);
+
+ entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0);
+
+ entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0);
+
+ entry_priv = rt2x00dev->rx->entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit);
+ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1);
+ rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0);
+
+ /*
+ * Enable global DMA configuration
+ */
+ rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0);
+
+ return 0;
+}
+
+static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_OFFSET0, &reg);
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */
+ rt2x00pci_register_write(rt2x00dev, BCN_OFFSET0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_OFFSET1, &reg);
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */
+ rt2x00pci_register_write(rt2x00dev, BCN_OFFSET1, reg);
+
+ rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
+ rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
+ rt2x00pci_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+
+ rt2x00pci_register_read(rt2x00dev, TX_LINK_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_MFB_ENABLE, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_MRQ_EN, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_RDG_EN, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_CF_ACK_EN, 1);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFB, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFS, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_LINK_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9);
+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10);
+ rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
+ if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION &&
+ rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION)
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
+ else
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_PSDU, 0);
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_MPDU, 0);
+ rt2x00pci_register_write(rt2x00dev, MAX_LEN_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f);
+
+ rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_AUTORESPONDER, 1);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MMODE, 0);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MREF, 0);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_DUAL_CTS_EN, 0);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0);
+ rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 8);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 8);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_RATE, 0x4004);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+ rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, 0x4084);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_RATE, 0x4004);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+ rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_RATE, 0x4084);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f);
+ rt2x00pci_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002);
+
+ rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES,
+ IEEE80211_MAX_RTS_THRESHOLD);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_FBK_EN, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca);
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
+ /*
+ * ASIC will keep garbage value after boot, clear encryption keys.
+ */
+ for (i = 0; i < 4; i++)
+ rt2x00pci_register_write(rt2x00dev,
+ SHARED_KEY_MODE_ENTRY(i), 0);
+
+ for (i = 0; i < 256; i++) {
+ u32 wcid[2] = { 0xffffffff, 0x00ffffff };
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
+ wcid, sizeof(wcid));
+
+ rt2x00pci_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
+ }
+
+ /*
+ * Clear all beacons
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE4, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE5, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE6, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
+
+ rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG0, &reg);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS0FBK, 0);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS1FBK, 0);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS2FBK, 1);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS3FBK, 2);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS4FBK, 3);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS5FBK, 4);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS6FBK, 5);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS7FBK, 6);
+ rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG1, &reg);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS8FBK, 8);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS9FBK, 8);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS10FBK, 9);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS11FBK, 10);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS12FBK, 11);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS13FBK, 12);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS14FBK, 13);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS15FBK, 14);
+ rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG0, &reg);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS0FBK, 8);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS1FBK, 8);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 9);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS3FBK, 10);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS4FBK, 11);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS5FBK, 12);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS6FBK, 13);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS7FBK, 14);
+ rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG1, &reg);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS0FBK, 0);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS1FBK, 0);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS2FBK, 1);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS3FBK, 2);
+ rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG1, reg);
+
+ /*
+ * We must clear the error counters.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT1, &reg);
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT2, &reg);
+ rt2x00pci_register_read(rt2x00dev, TX_STA_CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, TX_STA_CNT1, &reg);
+ rt2x00pci_register_read(rt2x00dev, TX_STA_CNT2, &reg);
+
+ return 0;
+}
+
+static int rt2800pci_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u32 reg;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_STATUS_CFG, &reg);
+ if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY))
+ return 0;
+
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n");
+ return -EACCES;
+}
+
+static int rt2800pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u8 value;
+
+ /*
+ * BBP was enabled after firmware was loaded,
+ * but we need to reactivate it now.
+ */
+ rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ msleep(1);
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ return 0;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+}
+
+static int rt2800pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ if (unlikely(rt2800pci_wait_bbp_rf_ready(rt2x00dev) ||
+ rt2800pci_wait_bbp_ready(rt2x00dev)))
+ return -EACCES;
+
+ rt2800pci_bbp_write(rt2x00dev, 65, 0x2c);
+ rt2800pci_bbp_write(rt2x00dev, 66, 0x38);
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x12);
+ rt2800pci_bbp_write(rt2x00dev, 70, 0x0a);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x10);
+ rt2800pci_bbp_write(rt2x00dev, 81, 0x37);
+ rt2800pci_bbp_write(rt2x00dev, 82, 0x62);
+ rt2800pci_bbp_write(rt2x00dev, 83, 0x6a);
+ rt2800pci_bbp_write(rt2x00dev, 84, 0x99);
+ rt2800pci_bbp_write(rt2x00dev, 86, 0x00);
+ rt2800pci_bbp_write(rt2x00dev, 91, 0x04);
+ rt2800pci_bbp_write(rt2x00dev, 92, 0x00);
+ rt2800pci_bbp_write(rt2x00dev, 103, 0x00);
+ rt2800pci_bbp_write(rt2x00dev, 105, 0x05);
+
+ if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x16);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x12);
+ }
+
+ if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION)
+ rt2800pci_bbp_write(rt2x00dev, 84, 0x19);
+
+ if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
+ rt2800pci_bbp_write(rt2x00dev, 31, 0x08);
+ rt2800pci_bbp_write(rt2x00dev, 78, 0x0e);
+ rt2800pci_bbp_write(rt2x00dev, 80, 0x08);
+ }
+
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ rt2800pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+
+ return 0;
+}
+
+static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev,
+ bool bw40, u8 rfcsr24, u8 filter_target)
+{
+ unsigned int i;
+ u8 bbp;
+ u8 rfcsr;
+ u8 passband;
+ u8 stopband;
+ u8 overtuned = 0;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
+
+ rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40);
+ rt2800pci_bbp_write(rt2x00dev, 4, bbp);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1);
+ rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr);
+
+ /*
+ * Set power & frequency of passband test tone
+ */
+ rt2800pci_bbp_write(rt2x00dev, 24, 0);
+
+ for (i = 0; i < 100; i++) {
+ rt2800pci_bbp_write(rt2x00dev, 25, 0x90);
+ msleep(1);
+
+ rt2800pci_bbp_read(rt2x00dev, 55, &passband);
+ if (passband)
+ break;
+ }
+
+ /*
+ * Set power & frequency of stopband test tone
+ */
+ rt2800pci_bbp_write(rt2x00dev, 24, 0x06);
+
+ for (i = 0; i < 100; i++) {
+ rt2800pci_bbp_write(rt2x00dev, 25, 0x90);
+ msleep(1);
+
+ rt2800pci_bbp_read(rt2x00dev, 55, &stopband);
+
+ if ((passband - stopband) <= filter_target) {
+ rfcsr24++;
+ overtuned += ((passband - stopband) == filter_target);
+ } else
+ break;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
+ }
+
+ rfcsr24 -= !!overtuned;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
+ return rfcsr24;
+}
+
+static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+{
+ u8 rfcsr;
+ u8 bbp;
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3022))
+ return 0;
+
+ /*
+ * Init RF calibration.
+ */
+ rt2800pci_rfcsr_read(rt2x00dev, 30, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
+ rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr);
+ msleep(1);
+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
+ rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+ rt2800pci_rfcsr_write(rt2x00dev, 0, 0x50);
+ rt2800pci_rfcsr_write(rt2x00dev, 1, 0x01);
+ rt2800pci_rfcsr_write(rt2x00dev, 2, 0xf7);
+ rt2800pci_rfcsr_write(rt2x00dev, 3, 0x75);
+ rt2800pci_rfcsr_write(rt2x00dev, 4, 0x40);
+ rt2800pci_rfcsr_write(rt2x00dev, 5, 0x03);
+ rt2800pci_rfcsr_write(rt2x00dev, 6, 0x02);
+ rt2800pci_rfcsr_write(rt2x00dev, 7, 0x50);
+ rt2800pci_rfcsr_write(rt2x00dev, 8, 0x39);
+ rt2800pci_rfcsr_write(rt2x00dev, 9, 0x0f);
+ rt2800pci_rfcsr_write(rt2x00dev, 10, 0x60);
+ rt2800pci_rfcsr_write(rt2x00dev, 11, 0x21);
+ rt2800pci_rfcsr_write(rt2x00dev, 12, 0x75);
+ rt2800pci_rfcsr_write(rt2x00dev, 13, 0x75);
+ rt2800pci_rfcsr_write(rt2x00dev, 14, 0x90);
+ rt2800pci_rfcsr_write(rt2x00dev, 15, 0x58);
+ rt2800pci_rfcsr_write(rt2x00dev, 16, 0xb3);
+ rt2800pci_rfcsr_write(rt2x00dev, 17, 0x92);
+ rt2800pci_rfcsr_write(rt2x00dev, 18, 0x2c);
+ rt2800pci_rfcsr_write(rt2x00dev, 19, 0x02);
+ rt2800pci_rfcsr_write(rt2x00dev, 20, 0xba);
+ rt2800pci_rfcsr_write(rt2x00dev, 21, 0xdb);
+ rt2800pci_rfcsr_write(rt2x00dev, 22, 0x00);
+ rt2800pci_rfcsr_write(rt2x00dev, 23, 0x31);
+ rt2800pci_rfcsr_write(rt2x00dev, 24, 0x08);
+ rt2800pci_rfcsr_write(rt2x00dev, 25, 0x01);
+ rt2800pci_rfcsr_write(rt2x00dev, 26, 0x25);
+ rt2800pci_rfcsr_write(rt2x00dev, 27, 0x23);
+ rt2800pci_rfcsr_write(rt2x00dev, 28, 0x13);
+ rt2800pci_rfcsr_write(rt2x00dev, 29, 0x83);
+
+ /*
+ * Set RX Filter calibration for 20MHz and 40MHz
+ */
+ rt2x00dev->calibration[0] =
+ rt2800pci_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
+ rt2x00dev->calibration[1] =
+ rt2800pci_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
+
+ /*
+ * Set back to initial state
+ */
+ rt2800pci_bbp_write(rt2x00dev, 24, 0);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0);
+ rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr);
+
+ /*
+ * set BBP back to BW20
+ */
+ rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
+ rt2800pci_bbp_write(rt2x00dev, 4, bbp);
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
+ (state == STATE_RADIO_RX_ON) ||
+ (state == STATE_RADIO_RX_ON_LINK));
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+}
+
+static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_ON);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ }
+
+ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC0_DMA_DONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC1_DMA_DONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC2_DMA_DONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AC3_DMA_DONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_HCCA_DMA_DONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_MGMT_DMA_DONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_MCU_COMMAND, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RXTX_COHERENT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, mask);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+}
+
+static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u32 reg;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
+ !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
+ return 0;
+
+ msleep(1);
+ }
+
+ ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
+ return -EACCES;
+}
+
+static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 word;
+
+ /*
+ * Initialize all registers.
+ */
+ if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+ rt2800pci_init_queues(rt2x00dev) ||
+ rt2800pci_init_registers(rt2x00dev) ||
+ rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+ rt2800pci_init_bbp(rt2x00dev) ||
+ rt2800pci_init_rfcsr(rt2x00dev)))
+ return -EIO;
+
+ /*
+ * Send signal to firmware during boot time.
+ */
+ rt2800pci_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+
+ /*
+ * Enable RX.
+ */
+ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ /*
+ * Initialize LED control
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
+ rt2800pci_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
+ rt2800pci_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
+ rt2800pci_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ return 0;
+}
+
+static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280);
+
+ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
+ /* Wait for DMA, ignore error */
+ rt2800pci_wait_wpdma_ready(rt2x00dev);
+}
+
+static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ /*
+ * Always put the device to sleep (even when we intend to wakeup!)
+ * if the device is booting and wasn't asleep it will return
+ * failure when attempting to wakeup.
+ */
+ rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2);
+
+ if (state == STATE_AWAKE) {
+ rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0);
+ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
+ }
+
+ return 0;
+}
+
+static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ /*
+ * Before the radio can be enabled, the device first has
+ * to be woken up. After that it needs a bit of time
+ * to be fully awake and then the radio can be enabled.
+ */
+ rt2800pci_set_state(rt2x00dev, STATE_AWAKE);
+ msleep(1);
+ retval = rt2800pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ /*
+ * After the radio has been disabled, the device should
+ * be put to sleep for powersaving.
+ */
+ rt2800pci_disable_radio(rt2x00dev);
+ rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_ON_LINK:
+ case STATE_RADIO_RX_OFF:
+ case STATE_RADIO_RX_OFF_LINK:
+ rt2800pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_OFF:
+ rt2800pci_toggle_irq(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2800pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ if (unlikely(retval))
+ ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
+ state, retval);
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct txentry_desc *txdesc)
+{
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ __le32 *txd = skbdesc->desc;
+ __le32 *txwi = (__le32 *)(skb->data - rt2x00dev->hw->extra_tx_headroom);
+ u32 word;
+
+ /*
+ * Initialize TX Info descriptor
+ */
+ rt2x00_desc_read(txwi, 0, &word);
+ rt2x00_set_field32(&word, TXWI_W0_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
+ rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
+ rt2x00_set_field32(&word, TXWI_W0_TS,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_AMPDU,
+ test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
+ rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs);
+ rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
+ rt2x00_set_field32(&word, TXWI_W0_BW,
+ test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
+ test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
+ rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
+ rt2x00_desc_write(txwi, 0, word);
+
+ rt2x00_desc_read(txwi, 1, &word);
+ rt2x00_set_field32(&word, TXWI_W1_ACK,
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W1_NSEQ,
+ test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
+ rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
+ test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
+ (skbdesc->entry->entry_idx + 1) : 0xff);
+ rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
+ skb->len - txdesc->l2pad);
+ rt2x00_set_field32(&word, TXWI_W1_PACKETID,
+ skbdesc->entry->queue->qid + 1);
+ rt2x00_desc_write(txwi, 1, word);
+
+ /*
+ * Always write 0 to IV/EIV fields, hardware will insert the IV
+ * from the IVEIV register when ENTRY_TXD_ENCRYPT_IV is set to 0.
+ * When ENTRY_TXD_ENCRYPT_IV is set to 1 it will use the IV data
+ * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
+ * crypto entry in the registers should be used to encrypt the frame.
+ */
+ _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
+ _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
+
+ /*
+ * The buffers pointed by SD_PTR0/SD_LEN0 and SD_PTR1/SD_LEN1
+ * must contains a TXWI structure + 802.11 header + padding + 802.11
+ * data. We choose to have SD_PTR0/SD_LEN0 only contains TXWI and
+ * SD_PTR1/SD_LEN1 contains 802.11 header + padding + 802.11
+ * data. It means that LAST_SEC0 is always 0.
+ */
+
+ /*
+ * Initialize TX descriptor
+ */
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_SD_PTR0, skbdesc->skb_dma);
+ rt2x00_desc_write(txd, 0, word);
+
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len);
+ rt2x00_set_field32(&word, TXD_W1_LAST_SEC1,
+ !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W1_BURST,
+ test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
+ rt2x00dev->hw->extra_tx_headroom);
+ rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
+ rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
+ skbdesc->skb_dma + rt2x00dev->hw->extra_tx_headroom);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 3, &word);
+ rt2x00_set_field32(&word, TXD_W3_WIV,
+ !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
+ rt2x00_desc_write(txd, 3, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2800pci_write_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ unsigned int beacon_base;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ /*
+ * Write entire beacon with descriptor to register.
+ */
+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev,
+ beacon_base,
+ skbdesc->desc, skbdesc->desc_len);
+ rt2x00pci_register_multiwrite(rt2x00dev,
+ beacon_base + skbdesc->desc_len,
+ entry->skb->data, entry->skb->len);
+
+ /*
+ * Clean up beacon skb.
+ */
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+}
+
+static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ const enum data_queue_qid queue_idx)
+{
+ struct data_queue *queue;
+ unsigned int idx, qidx = 0;
+ u32 reg;
+
+ if (queue_idx == QID_BEACON) {
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ }
+ return;
+ }
+
+ if (queue_idx > QID_HCCA && queue_idx != QID_MGMT)
+ return;
+
+ queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+ idx = queue->index[Q_INDEX];
+
+ if (queue_idx == QID_MGMT)
+ qidx = 5;
+ else
+ qidx = queue_idx;
+
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
+}
+
+static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
+ const enum data_queue_qid qid)
+{
+ u32 reg;
+
+ if (qid == QID_BEACON) {
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, 0);
+ return;
+ }
+
+ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE));
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK));
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI));
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO));
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2800pci_fill_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ __le32 *rxd = entry_priv->desc;
+ __le32 *rxwi = (__le32 *)entry->skb->data;
+ u32 rxd3;
+ u32 rxwi0;
+ u32 rxwi1;
+ u32 rxwi2;
+ u32 rxwi3;
+
+ rt2x00_desc_read(rxd, 3, &rxd3);
+ rt2x00_desc_read(rxwi, 0, &rxwi0);
+ rt2x00_desc_read(rxwi, 1, &rxwi1);
+ rt2x00_desc_read(rxwi, 2, &rxwi2);
+ rt2x00_desc_read(rxwi, 3, &rxwi3);
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_CRC_ERROR))
+ rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+ /*
+ * Unfortunately we don't know the cipher type used during
+ * decryption. This prevents us from correct providing
+ * correct statistics through debugfs.
+ */
+ rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
+ rxdesc->cipher_status =
+ rt2x00_get_field32(rxd3, RXD_W3_CIPHER_ERROR);
+ }
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_DECRYPTED)) {
+ /*
+ * Hardware has stripped IV/EIV data from 802.11 frame during
+ * decryption. Unfortunately the descriptor doesn't contain
+ * any fields with the EIV/IV data either, so they can't
+ * be restored by rt2x00lib.
+ */
+ rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+
+ if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+ rxdesc->flags |= RX_FLAG_DECRYPTED;
+ else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+ rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+ }
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
+ rxdesc->dev_flags |= RXDONE_MY_BSS;
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) {
+ rxdesc->dev_flags |= RXDONE_L2PAD;
+ skbdesc->flags |= SKBDESC_L2_PADDED;
+ }
+
+ if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
+ rxdesc->flags |= RX_FLAG_SHORT_GI;
+
+ if (rt2x00_get_field32(rxwi1, RXWI_W1_BW))
+ rxdesc->flags |= RX_FLAG_40MHZ;
+
+ /*
+ * Detect RX rate, always use MCS as signal type.
+ */
+ rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
+ rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE);
+ rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS);
+
+ /*
+ * Mask of 0x8 bit to remove the short preamble flag.
+ */
+ if (rxdesc->rate_mode == RATE_MODE_CCK)
+ rxdesc->signal &= ~0x8;
+
+ rxdesc->rssi =
+ (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
+ rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
+
+ rxdesc->noise =
+ (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) +
+ rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2;
+
+ rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
+
+ /*
+ * Set RX IDX in register to inform hardware that we have handled
+ * this entry and it is available for reuse again.
+ */
+ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
+
+ /*
+ * Remove TXWI descriptor from start of buffer.
+ */
+ skb_pull(entry->skb, RXWI_DESC_SIZE);
+ skb_trim(entry->skb, rxdesc->size);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ struct queue_entry *entry;
+ struct queue_entry *entry_done;
+ struct queue_entry_priv_pci *entry_priv;
+ struct txdone_entry_desc txdesc;
+ u32 word;
+ u32 reg;
+ u32 old_reg;
+ unsigned int type;
+ unsigned int index;
+ u16 mcs, real_mcs;
+
+ /*
+ * During each loop we will compare the freshly read
+ * TX_STA_FIFO register value with the value read from
+ * the previous loop. If the 2 values are equal then
+ * we should stop processing because the chance it
+ * quite big that the device has been unplugged and
+ * we risk going into an endless loop.
+ */
+ old_reg = 0;
+
+ while (1) {
+ rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &reg);
+ if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
+ break;
+
+ if (old_reg == reg)
+ break;
+ old_reg = reg;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * queue identication number.
+ */
+ type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
+ if (type >= QID_RX)
+ continue;
+
+ queue = rt2x00queue_get_queue(rt2x00dev, type);
+ if (unlikely(!queue))
+ continue;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * index number.
+ */
+ index = rt2x00_get_field32(reg, TX_STA_FIFO_WCID) - 1;
+ if (unlikely(index >= queue->limit))
+ continue;
+
+ entry = &queue->entries[index];
+ entry_priv = entry->priv_data;
+ rt2x00_desc_read((__le32 *)entry->skb->data, 0, &word);
+
+ entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ while (entry != entry_done) {
+ /*
+ * Catch up.
+ * Just report any entries we missed as failed.
+ */
+ WARNING(rt2x00dev,
+ "TX status report missed for entry %d\n",
+ entry_done->entry_idx);
+
+ txdesc.flags = 0;
+ __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
+ txdesc.retry = 0;
+
+ rt2x00lib_txdone(entry_done, &txdesc);
+ entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ }
+
+ /*
+ * Obtain the status about this packet.
+ */
+ txdesc.flags = 0;
+ if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS))
+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+ else
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
+
+ /*
+ * Ralink has a retry mechanism using a global fallback
+ * table. We setup this fallback table to try immediate
+ * lower rate for all rates. In the TX_STA_FIFO,
+ * the MCS field contains the MCS used for the successfull
+ * transmission. If the first transmission succeed,
+ * we have mcs == tx_mcs. On the second transmission,
+ * we have mcs = tx_mcs - 1. So the number of
+ * retry is (tx_mcs - mcs).
+ */
+ mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
+ real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
+ __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+ txdesc.retry = mcs - min(mcs, real_mcs);
+
+ rt2x00lib_txdone(entry, &txdesc);
+ }
+}
+
+static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /* Read status and ACK all interrupts */
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * 1 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
+ rt2800pci_txdone(rt2x00dev);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 word;
+ u8 *mac;
+ u8 default_lna_gain;
+
+ /*
+ * Read EEPROM into buffer
+ */
+ switch(rt2x00dev->chip.rt) {
+ case RT2880:
+ case RT3052:
+ rt2800pci_read_eeprom_soc(rt2x00dev);
+ break;
+ case RT3090:
+ rt2800pci_read_eeprom_efuse(rt2x00dev);
+ break;
+ default:
+ rt2800pci_read_eeprom_pci(rt2x00dev);
+ break;
+ }
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
+ /*
+ * There is a max of 2 RX streams for RT2860 series
+ */
+ if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+ if ((word & 0x00ff) == 0x00ff) {
+ rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+ rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
+ LED_MODE_TXRX_ACTIVITY);
+ rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ }
+
+ /*
+ * During the LNA validation we are going to use
+ * lna0 as correct value. Note that EEPROM_LNA
+ * is never validated.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
+ default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
+ if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
+ rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
+ default_lna_gain);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
+ if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
+ rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
+ default_lna_gain);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
+
+ return 0;
+}
+
+static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip_rf(rt2x00dev, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2850) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2720) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2750) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3020) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2020) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3022)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->default_ant.tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
+ rt2x00dev->default_ant.rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
+
+ /*
+ * Read frequency offset and RF programming sequence.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+ /*
+ * Read external LNA informations.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+ __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+
+ /*
+ * Store led settings, for correct led behaviour.
+ */
+#ifdef CONFIG_RT2X00_LIB_LEDS
+ rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
+ rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
+ rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg);
+#endif /* CONFIG_RT2X00_LIB_LEDS */
+
+ return 0;
+}
+
+/*
+ * RF value list for rt2860
+ * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
+ */
+static const struct rf_channel rf_vals[] = {
+ { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b },
+ { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f },
+ { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b },
+ { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f },
+ { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b },
+ { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f },
+ { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b },
+ { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f },
+ { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b },
+ { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f },
+ { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b },
+ { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f },
+ { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b },
+ { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 },
+ { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 },
+ { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 },
+ { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 },
+ { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b },
+ { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b },
+ { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 },
+ { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 },
+ { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b },
+ { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 },
+ { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 },
+ { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
+ { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
+ { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
+ { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
+ { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
+ { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
+ { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
+ { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 },
+ { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 },
+ { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 },
+ { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b },
+ { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 },
+ { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b },
+ { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 },
+ { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b },
+ { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 },
+
+ /* 802.11 UNII */
+ { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 },
+ { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 },
+ { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f },
+ { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f },
+ { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 },
+ { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 },
+ { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 },
+
+ /* 802.11 Japan */
+ { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b },
+ { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 },
+ { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b },
+ { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 },
+ { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 },
+ { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b },
+ { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 },
+};
+
+static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ struct channel_info *info;
+ char *tx_power1;
+ char *tx_power2;
+ unsigned int i;
+ u16 eeprom;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags =
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK;
+ rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->supported_bands = SUPPORT_BAND_2GHZ;
+ spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2820) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2720) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3020) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3021) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3022) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2020) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3052)) {
+ spec->num_channels = 14;
+ spec->channels = rf_vals;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2750)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
+ spec->num_channels = ARRAY_SIZE(rf_vals);
+ spec->channels = rf_vals;
+ }
+
+ /*
+ * Initialize HT information.
+ */
+ spec->ht.ht_supported = true;
+ spec->ht.cap =
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_TX_STBC |
+ IEEE80211_HT_CAP_RX_STBC |
+ IEEE80211_HT_CAP_PSMP_SUPPORT;
+ spec->ht.ampdu_factor = 3;
+ spec->ht.ampdu_density = 4;
+ spec->ht.mcs.tx_params =
+ IEEE80211_HT_MCS_TX_DEFINED |
+ IEEE80211_HT_MCS_TX_RX_DIFF |
+ ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+
+ switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
+ case 3:
+ spec->ht.mcs.rx_mask[2] = 0xff;
+ case 2:
+ spec->ht.mcs.rx_mask[1] = 0xff;
+ case 1:
+ spec->ht.mcs.rx_mask[0] = 0xff;
+ spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
+ break;
+ }
+
+ /*
+ * Create channel information array
+ */
+ info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ spec->channels_info = info;
+
+ tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
+ tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
+
+ for (i = 0; i < 14; i++) {
+ info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]);
+ info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]);
+ }
+
+ if (spec->num_channels > 14) {
+ tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
+ tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
+
+ for (i = 14; i < spec->num_channels; i++) {
+ info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]);
+ info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2800pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2800pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ retval = rt2800pci_probe_hw_mode(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * This device has multiple filters for control frames
+ * and has a separate filter for PS Poll frames.
+ */
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
+
+ /*
+ * This device requires firmware.
+ */
+ if (!rt2x00_rt(&rt2x00dev->chip, RT2880) &&
+ !rt2x00_rt(&rt2x00dev->chip, RT3052))
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
+ if (!modparam_nohwcrypt)
+ __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2800pci_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
+ u32 *iv32, u16 *iv16)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct mac_iveiv_entry iveiv_entry;
+ u32 offset;
+
+ offset = MAC_IVEIV_ENTRY(hw_key_idx);
+ rt2x00pci_register_multiread(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
+
+ memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16));
+ memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32));
+}
+
+static int rt2800pci_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+ bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD);
+
+ rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES, value);
+ rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg);
+
+ return 0;
+}
+
+static int rt2800pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_queue *queue;
+ struct rt2x00_field32 field;
+ int retval;
+ u32 reg;
+ u32 offset;
+
+ /*
+ * First pass the configuration through rt2x00lib, that will
+ * update the queue settings and validate the input. After that
+ * we are free to update the registers based on the value
+ * in the queue parameter.
+ */
+ retval = rt2x00mac_conf_tx(hw, queue_idx, params);
+ if (retval)
+ return retval;
+
+ /*
+ * We only need to perform additional register initialization
+ * for WMM queues/
+ */
+ if (queue_idx >= 4)
+ return 0;
+
+ queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+
+ /* Update WMM TXOP register */
+ offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2)));
+ field.bit_offset = (queue_idx & 1) * 16;
+ field.bit_mask = 0xffff << field.bit_offset;
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, field, queue->txop);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ /* Update WMM registers */
+ field.bit_offset = queue_idx * 4;
+ field.bit_mask = 0xf << field.bit_offset;
+
+ rt2x00pci_register_read(rt2x00dev, WMM_AIFSN_CFG, &reg);
+ rt2x00_set_field32(&reg, field, queue->aifs);
+ rt2x00pci_register_write(rt2x00dev, WMM_AIFSN_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, WMM_CWMIN_CFG, &reg);
+ rt2x00_set_field32(&reg, field, queue->cw_min);
+ rt2x00pci_register_write(rt2x00dev, WMM_CWMIN_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, WMM_CWMAX_CFG, &reg);
+ rt2x00_set_field32(&reg, field, queue->cw_max);
+ rt2x00pci_register_write(rt2x00dev, WMM_CWMAX_CFG, reg);
+
+ /* Update EDCA registers */
+ offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx);
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_TX_OP, queue->txop);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_AIFSN, queue->aifs);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMIN, queue->cw_min);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMAX, queue->cw_max);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ return 0;
+}
+
+static u64 rt2800pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW1, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32;
+ rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW0, &reg);
+ tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD);
+
+ return tsf;
+}
+
+static const struct ieee80211_ops rt2800pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .configure_filter = rt2x00mac_configure_filter,
+ .set_key = rt2x00mac_set_key,
+ .get_stats = rt2x00mac_get_stats,
+ .get_tkip_seq = rt2800pci_get_tkip_seq,
+ .set_rts_threshold = rt2800pci_set_rts_threshold,
+ .bss_info_changed = rt2x00mac_bss_info_changed,
+ .conf_tx = rt2800pci_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt2800pci_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
+};
+
+static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
+ .irq_handler = rt2800pci_interrupt,
+ .probe_hw = rt2800pci_probe_hw,
+ .get_firmware_name = rt2800pci_get_firmware_name,
+ .check_firmware = rt2800pci_check_firmware,
+ .load_firmware = rt2800pci_load_firmware,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .get_entry_state = rt2800pci_get_entry_state,
+ .clear_entry = rt2800pci_clear_entry,
+ .set_device_state = rt2800pci_set_device_state,
+ .rfkill_poll = rt2800pci_rfkill_poll,
+ .link_stats = rt2800pci_link_stats,
+ .reset_tuner = rt2800pci_reset_tuner,
+ .link_tuner = rt2800pci_link_tuner,
+ .write_tx_desc = rt2800pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .write_beacon = rt2800pci_write_beacon,
+ .kick_tx_queue = rt2800pci_kick_tx_queue,
+ .kill_tx_queue = rt2800pci_kill_tx_queue,
+ .fill_rxdone = rt2800pci_fill_rxdone,
+ .config_shared_key = rt2800pci_config_shared_key,
+ .config_pairwise_key = rt2800pci_config_pairwise_key,
+ .config_filter = rt2800pci_config_filter,
+ .config_intf = rt2800pci_config_intf,
+ .config_erp = rt2800pci_config_erp,
+ .config_ant = rt2800pci_config_ant,
+ .config = rt2800pci_config,
+};
+
+static const struct data_queue_desc rt2800pci_queue_rx = {
+ .entry_num = RX_ENTRIES,
+ .data_size = AGGREGATION_SIZE,
+ .desc_size = RXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci),
+};
+
+static const struct data_queue_desc rt2800pci_queue_tx = {
+ .entry_num = TX_ENTRIES,
+ .data_size = AGGREGATION_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci),
+};
+
+static const struct data_queue_desc rt2800pci_queue_bcn = {
+ .entry_num = 8 * BEACON_ENTRIES,
+ .data_size = 0, /* No DMA required for beacons */
+ .desc_size = TXWI_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci),
+};
+
+static const struct rt2x00_ops rt2800pci_ops = {
+ .name = KBUILD_MODNAME,
+ .max_sta_intf = 1,
+ .max_ap_intf = 8,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
+ .rx = &rt2800pci_queue_rx,
+ .tx = &rt2800pci_queue_tx,
+ .bcn = &rt2800pci_queue_bcn,
+ .lib = &rt2800pci_rt2x00_ops,
+ .hw = &rt2800pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2800pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2800pci module information.
+ */
+static struct pci_device_id rt2800pci_device_table[] = {
+ { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2860 PCI & PCMCIA chipset based cards");
+#ifdef CONFIG_RT2800PCI_PCI
+MODULE_FIRMWARE(FIRMWARE_RT2860);
+MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
+#endif /* CONFIG_RT2800PCI_PCI */
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_RT2800PCI_WISOC
+#if defined(CONFIG_RALINK_RT288X)
+__rt2x00soc_probe(RT2880, &rt2800pci_ops);
+#elif defined(CONFIG_RALINK_RT305X)
+__rt2x00soc_probe(RT3052, &rt2800pci_ops);
+#endif
+
+static struct platform_driver rt2800soc_driver = {
+ .driver = {
+ .name = "rt2800_wmac",
+ .owner = THIS_MODULE,
+ .mod_name = KBUILD_MODNAME,
+ },
+ .probe = __rt2x00soc_probe,
+ .remove = __devexit_p(rt2x00soc_remove),
+ .suspend = rt2x00soc_suspend,
+ .resume = rt2x00soc_resume,
+};
+#endif /* CONFIG_RT2800PCI_WISOC */
+
+#ifdef CONFIG_RT2800PCI_PCI
+static struct pci_driver rt2800pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rt2800pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+#endif /* CONFIG_RT2800PCI_PCI */
+
+static int __init rt2800pci_init(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_RT2800PCI_WISOC
+ ret = platform_driver_register(&rt2800soc_driver);
+ if (ret)
+ return ret;
+#endif
+#ifdef CONFIG_RT2800PCI_PCI
+ ret = pci_register_driver(&rt2800pci_driver);
+ if (ret) {
+#ifdef CONFIG_RT2800PCI_WISOC
+ platform_driver_unregister(&rt2800soc_driver);
+#endif
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+static void __exit rt2800pci_exit(void)
+{
+#ifdef CONFIG_RT2800PCI_PCI
+ pci_unregister_driver(&rt2800pci_driver);
+#endif
+#ifdef CONFIG_RT2800PCI_WISOC
+ platform_driver_unregister(&rt2800soc_driver);
+#endif
+}
+
+module_init(rt2800pci_init);
+module_exit(rt2800pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h
new file mode 100644
index 00000000000..85690881522
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2800pci.h
@@ -0,0 +1,1960 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2800pci
+ Abstract: Data structures and registers for the rt2800pci module.
+ Supported chipsets: RT2800E & RT2800ED.
+ */
+
+#ifndef RT2800PCI_H
+#define RT2800PCI_H
+
+/*
+ * RF chip defines.
+ *
+ * RF2820 2.4G 2T3R
+ * RF2850 2.4G/5G 2T3R
+ * RF2720 2.4G 1T2R
+ * RF2750 2.4G/5G 1T2R
+ * RF3020 2.4G 1T1R
+ * RF2020 2.4G B/G
+ * RF3021 2.4G 1T2R
+ * RF3022 2.4G 2T2R
+ * RF3052 2.4G 2T2R
+ */
+#define RF2820 0x0001
+#define RF2850 0x0002
+#define RF2720 0x0003
+#define RF2750 0x0004
+#define RF3020 0x0005
+#define RF2020 0x0006
+#define RF3021 0x0007
+#define RF3022 0x0008
+#define RF3052 0x0009
+
+/*
+ * RT2860 version
+ */
+#define RT2860C_VERSION 0x28600100
+#define RT2860D_VERSION 0x28600101
+#define RT2880E_VERSION 0x28720200
+#define RT2883_VERSION 0x28830300
+#define RT3070_VERSION 0x30700200
+
+/*
+ * Signal information.
+ * Default offset is required for RSSI <-> dBm conversion.
+ */
+#define DEFAULT_RSSI_OFFSET 120 /* FIXME */
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x1000
+#define CSR_REG_SIZE 0x0800
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0110
+#define BBP_BASE 0x0000
+#define BBP_SIZE 0x0080
+#define RF_BASE 0x0004
+#define RF_SIZE 0x0010
+
+/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES 4
+
+/*
+ * PCI registers.
+ */
+
+/*
+ * E2PROM_CSR: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE: 0: 93c46, 1:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR 0x0004
+#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001)
+#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002)
+#define E2PROM_CSR_DATA_IN FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008)
+#define E2PROM_CSR_TYPE FIELD32(0x00000030)
+#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
+#define E2PROM_CSR_RELOAD FIELD32(0x00000080)
+
+/*
+ * INT_SOURCE_CSR: Interrupt source register.
+ * Write one to clear corresponding bit.
+ * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c
+ */
+#define INT_SOURCE_CSR 0x0200
+#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001)
+#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002)
+#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004)
+#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008)
+#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010)
+#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020)
+#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040)
+#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080)
+#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100)
+#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200)
+#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400)
+#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800)
+#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000)
+#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000)
+#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000)
+#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000)
+#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000)
+#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000)
+
+/*
+ * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF.
+ */
+#define INT_MASK_CSR 0x0204
+#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001)
+#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002)
+#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004)
+#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008)
+#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010)
+#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020)
+#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040)
+#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080)
+#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100)
+#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200)
+#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400)
+#define INT_MASK_CSR_TBTT FIELD32(0x00000800)
+#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000)
+#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000)
+#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000)
+#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000)
+#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000)
+#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000)
+
+/*
+ * WPDMA_GLO_CFG
+ */
+#define WPDMA_GLO_CFG 0x0208
+#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001)
+#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002)
+#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004)
+#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008)
+#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030)
+#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040)
+#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080)
+#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00)
+#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000)
+
+/*
+ * WPDMA_RST_IDX
+ */
+#define WPDMA_RST_IDX 0x020c
+#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001)
+#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002)
+#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004)
+#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008)
+#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010)
+#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020)
+#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000)
+
+/*
+ * DELAY_INT_CFG
+ */
+#define DELAY_INT_CFG 0x0210
+#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff)
+#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00)
+#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000)
+#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000)
+#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000)
+#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000)
+
+/*
+ * WMM_AIFSN_CFG: Aifsn for each EDCA AC
+ * AIFSN0: AC_BE
+ * AIFSN1: AC_BK
+ * AIFSN1: AC_VI
+ * AIFSN1: AC_VO
+ */
+#define WMM_AIFSN_CFG 0x0214
+#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f)
+#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0)
+#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00)
+#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000)
+
+/*
+ * WMM_CWMIN_CSR: CWmin for each EDCA AC
+ * CWMIN0: AC_BE
+ * CWMIN1: AC_BK
+ * CWMIN1: AC_VI
+ * CWMIN1: AC_VO
+ */
+#define WMM_CWMIN_CFG 0x0218
+#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f)
+#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0)
+#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00)
+#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000)
+
+/*
+ * WMM_CWMAX_CSR: CWmax for each EDCA AC
+ * CWMAX0: AC_BE
+ * CWMAX1: AC_BK
+ * CWMAX1: AC_VI
+ * CWMAX1: AC_VO
+ */
+#define WMM_CWMAX_CFG 0x021c
+#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f)
+#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0)
+#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00)
+#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000)
+
+/*
+ * AC_TXOP0: AC_BK/AC_BE TXOP register
+ * AC0TXOP: AC_BK in unit of 32us
+ * AC1TXOP: AC_BE in unit of 32us
+ */
+#define WMM_TXOP0_CFG 0x0220
+#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff)
+#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP1: AC_VO/AC_VI TXOP register
+ * AC2TXOP: AC_VI in unit of 32us
+ * AC3TXOP: AC_VO in unit of 32us
+ */
+#define WMM_TXOP1_CFG 0x0224
+#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff)
+#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000)
+
+/*
+ * GPIO_CTRL_CFG:
+ */
+#define GPIO_CTRL_CFG 0x0228
+#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001)
+#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002)
+#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004)
+#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008)
+#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010)
+#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020)
+#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040)
+#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080)
+#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100)
+
+/*
+ * MCU_CMD_CFG
+ */
+#define MCU_CMD_CFG 0x022c
+
+/*
+ * AC_BK register offsets
+ */
+#define TX_BASE_PTR0 0x0230
+#define TX_MAX_CNT0 0x0234
+#define TX_CTX_IDX0 0x0238
+#define TX_DTX_IDX0 0x023c
+
+/*
+ * AC_BE register offsets
+ */
+#define TX_BASE_PTR1 0x0240
+#define TX_MAX_CNT1 0x0244
+#define TX_CTX_IDX1 0x0248
+#define TX_DTX_IDX1 0x024c
+
+/*
+ * AC_VI register offsets
+ */
+#define TX_BASE_PTR2 0x0250
+#define TX_MAX_CNT2 0x0254
+#define TX_CTX_IDX2 0x0258
+#define TX_DTX_IDX2 0x025c
+
+/*
+ * AC_VO register offsets
+ */
+#define TX_BASE_PTR3 0x0260
+#define TX_MAX_CNT3 0x0264
+#define TX_CTX_IDX3 0x0268
+#define TX_DTX_IDX3 0x026c
+
+/*
+ * HCCA register offsets
+ */
+#define TX_BASE_PTR4 0x0270
+#define TX_MAX_CNT4 0x0274
+#define TX_CTX_IDX4 0x0278
+#define TX_DTX_IDX4 0x027c
+
+/*
+ * MGMT register offsets
+ */
+#define TX_BASE_PTR5 0x0280
+#define TX_MAX_CNT5 0x0284
+#define TX_CTX_IDX5 0x0288
+#define TX_DTX_IDX5 0x028c
+
+/*
+ * Queue register offset macros
+ */
+#define TX_QUEUE_REG_OFFSET 0x10
+#define TX_BASE_PTR(__x) TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET)
+#define TX_MAX_CNT(__x) TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET)
+#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
+#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
+
+/*
+ * RX register offsets
+ */
+#define RX_BASE_PTR 0x0290
+#define RX_MAX_CNT 0x0294
+#define RX_CRX_IDX 0x0298
+#define RX_DRX_IDX 0x029c
+
+/*
+ * PBF_SYS_CTRL
+ * HOST_RAM_WRITE: enable Host program ram write selection
+ */
+#define PBF_SYS_CTRL 0x0400
+#define PBF_SYS_CTRL_READY FIELD32(0x00000080)
+#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000)
+
+/*
+ * HOST-MCU shared memory
+ */
+#define HOST_CMD_CSR 0x0404
+#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff)
+
+/*
+ * PBF registers
+ * Most are for debug. Driver doesn't touch PBF register.
+ */
+#define PBF_CFG 0x0408
+#define PBF_MAX_PCNT 0x040c
+#define PBF_CTRL 0x0410
+#define PBF_INT_STA 0x0414
+#define PBF_INT_ENA 0x0418
+
+/*
+ * BCN_OFFSET0:
+ */
+#define BCN_OFFSET0 0x042c
+#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff)
+#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00)
+#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000)
+#define BCN_OFFSET0_BCN3 FIELD32(0xff000000)
+
+/*
+ * BCN_OFFSET1:
+ */
+#define BCN_OFFSET1 0x0430
+#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff)
+#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00)
+#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000)
+#define BCN_OFFSET1_BCN7 FIELD32(0xff000000)
+
+/*
+ * PBF registers
+ * Most are for debug. Driver doesn't touch PBF register.
+ */
+#define TXRXQ_PCNT 0x0438
+#define PBF_DBG 0x043c
+
+/*
+ * RF registers
+ */
+#define RF_CSR_CFG 0x0500
+#define RF_CSR_CFG_DATA FIELD32(0x000000ff)
+#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00)
+#define RF_CSR_CFG_WRITE FIELD32(0x00010000)
+#define RF_CSR_CFG_BUSY FIELD32(0x00020000)
+
+/*
+ * EFUSE_CSR: RT3090 EEPROM
+ */
+#define EFUSE_CTRL 0x0580
+#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000)
+#define EFUSE_CTRL_MODE FIELD32(0x000000c0)
+#define EFUSE_CTRL_KICK FIELD32(0x40000000)
+
+/*
+ * EFUSE_DATA0
+ */
+#define EFUSE_DATA0 0x0590
+
+/*
+ * EFUSE_DATA1
+ */
+#define EFUSE_DATA1 0x0594
+
+/*
+ * EFUSE_DATA2
+ */
+#define EFUSE_DATA2 0x0598
+
+/*
+ * EFUSE_DATA3
+ */
+#define EFUSE_DATA3 0x059c
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ * ASIC_REV: 0
+ * ASIC_VER: 2860
+ */
+#define MAC_CSR0 0x1000
+#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff)
+#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000)
+
+/*
+ * MAC_SYS_CTRL:
+ */
+#define MAC_SYS_CTRL 0x1004
+#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001)
+#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002)
+#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004)
+#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008)
+#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010)
+#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020)
+#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040)
+#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080)
+
+/*
+ * MAC_ADDR_DW0: STA MAC register 0
+ */
+#define MAC_ADDR_DW0 0x1008
+#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff)
+#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00)
+#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000)
+#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_ADDR_DW1: STA MAC register 1
+ * UNICAST_TO_ME_MASK:
+ * Used to mask off bits from byte 5 of the MAC address
+ * to determine the UNICAST_TO_ME bit for RX frames.
+ * The full mask is complemented by BSS_ID_MASK:
+ * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK
+ */
+#define MAC_ADDR_DW1 0x100c
+#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff)
+#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00)
+#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_BSSID_DW0: BSSID register 0
+ */
+#define MAC_BSSID_DW0 0x1010
+#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff)
+#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00)
+#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000)
+#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_BSSID_DW1: BSSID register 1
+ * BSS_ID_MASK:
+ * 0: 1-BSSID mode (BSS index = 0)
+ * 1: 2-BSSID mode (BSS index: Byte5, bit 0)
+ * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1)
+ * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2)
+ * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the
+ * BSSID. This will make sure that those bits will be ignored
+ * when determining the MY_BSS of RX frames.
+ */
+#define MAC_BSSID_DW1 0x1014
+#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff)
+#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00)
+#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000)
+#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000)
+
+/*
+ * MAX_LEN_CFG: Maximum frame length register.
+ * MAX_MPDU: rt2860b max 16k bytes
+ * MAX_PSDU: Maximum PSDU length
+ * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16
+ */
+#define MAX_LEN_CFG 0x1018
+#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff)
+#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000)
+#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000)
+#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000)
+
+/*
+ * BBP_CSR_CFG: BBP serial control register
+ * VALUE: Register value to program into BBP
+ * REG_NUM: Selected BBP register
+ * READ_CONTROL: 0 write BBP, 1 read BBP
+ * BUSY: ASIC is busy executing BBP commands
+ * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks
+ * BBP_RW_MODE: 0 serial, 1 paralell
+ */
+#define BBP_CSR_CFG 0x101c
+#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff)
+#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00)
+#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000)
+#define BBP_CSR_CFG_BUSY FIELD32(0x00020000)
+#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000)
+#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000)
+
+/*
+ * RF_CSR_CFG0: RF control register
+ * REGID_AND_VALUE: Register value to program into RF
+ * BITWIDTH: Selected RF register
+ * STANDBYMODE: 0 high when standby, 1 low when standby
+ * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate
+ * BUSY: ASIC is busy executing RF commands
+ */
+#define RF_CSR_CFG0 0x1020
+#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff)
+#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000)
+#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff)
+#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000)
+#define RF_CSR_CFG0_SEL FIELD32(0x40000000)
+#define RF_CSR_CFG0_BUSY FIELD32(0x80000000)
+
+/*
+ * RF_CSR_CFG1: RF control register
+ * REGID_AND_VALUE: Register value to program into RF
+ * RFGAP: Gap between BB_CONTROL_RF and RF_LE
+ * 0: 3 system clock cycle (37.5usec)
+ * 1: 5 system clock cycle (62.5usec)
+ */
+#define RF_CSR_CFG1 0x1024
+#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff)
+#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000)
+
+/*
+ * RF_CSR_CFG2: RF control register
+ * VALUE: Register value to program into RF
+ * RFGAP: Gap between BB_CONTROL_RF and RF_LE
+ * 0: 3 system clock cycle (37.5usec)
+ * 1: 5 system clock cycle (62.5usec)
+ */
+#define RF_CSR_CFG2 0x1028
+#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff)
+
+/*
+ * LED_CFG: LED control
+ * color LED's:
+ * 0: off
+ * 1: blinking upon TX2
+ * 2: periodic slow blinking
+ * 3: always on
+ * LED polarity:
+ * 0: active low
+ * 1: active high
+ */
+#define LED_CFG 0x102c
+#define LED_CFG_ON_PERIOD FIELD32(0x000000ff)
+#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00)
+#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000)
+#define LED_CFG_R_LED_MODE FIELD32(0x03000000)
+#define LED_CFG_G_LED_MODE FIELD32(0x0c000000)
+#define LED_CFG_Y_LED_MODE FIELD32(0x30000000)
+#define LED_CFG_LED_POLAR FIELD32(0x40000000)
+
+/*
+ * XIFS_TIME_CFG: MAC timing
+ * CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX
+ * OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX
+ * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX
+ * when MAC doesn't reference BBP signal BBRXEND
+ * EIFS: unit 1us
+ * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer
+ *
+ */
+#define XIFS_TIME_CFG 0x1100
+#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff)
+#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00)
+#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000)
+#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000)
+#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000)
+
+/*
+ * BKOFF_SLOT_CFG:
+ */
+#define BKOFF_SLOT_CFG 0x1104
+#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff)
+#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00)
+
+/*
+ * NAV_TIME_CFG:
+ */
+#define NAV_TIME_CFG 0x1108
+#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff)
+#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00)
+#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000)
+#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000)
+
+/*
+ * CH_TIME_CFG: count as channel busy
+ */
+#define CH_TIME_CFG 0x110c
+
+/*
+ * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us
+ */
+#define PBF_LIFE_TIMER 0x1110
+
+/*
+ * BCN_TIME_CFG:
+ * BEACON_INTERVAL: in unit of 1/16 TU
+ * TSF_TICKING: Enable TSF auto counting
+ * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode
+ * BEACON_GEN: Enable beacon generator
+ */
+#define BCN_TIME_CFG 0x1114
+#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000)
+#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000)
+#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000)
+#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000)
+#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000)
+
+/*
+ * TBTT_SYNC_CFG:
+ */
+#define TBTT_SYNC_CFG 0x1118
+
+/*
+ * TSF_TIMER_DW0: Local lsb TSF timer, read-only
+ */
+#define TSF_TIMER_DW0 0x111c
+#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff)
+
+/*
+ * TSF_TIMER_DW1: Local msb TSF timer, read-only
+ */
+#define TSF_TIMER_DW1 0x1120
+#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff)
+
+/*
+ * TBTT_TIMER: TImer remains till next TBTT, read-only
+ */
+#define TBTT_TIMER 0x1124
+
+/*
+ * INT_TIMER_CFG:
+ */
+#define INT_TIMER_CFG 0x1128
+
+/*
+ * INT_TIMER_EN: GP-timer and pre-tbtt Int enable
+ */
+#define INT_TIMER_EN 0x112c
+
+/*
+ * CH_IDLE_STA: channel idle time
+ */
+#define CH_IDLE_STA 0x1130
+
+/*
+ * CH_BUSY_STA: channel busy time
+ */
+#define CH_BUSY_STA 0x1134
+
+/*
+ * MAC_STATUS_CFG:
+ * BBP_RF_BUSY: When set to 0, BBP and RF are stable.
+ * if 1 or higher one of the 2 registers is busy.
+ */
+#define MAC_STATUS_CFG 0x1200
+#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003)
+
+/*
+ * PWR_PIN_CFG:
+ */
+#define PWR_PIN_CFG 0x1204
+
+/*
+ * AUTOWAKEUP_CFG: Manual power control / status register
+ * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set
+ * AUTOWAKE: 0:sleep, 1:awake
+ */
+#define AUTOWAKEUP_CFG 0x1208
+#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff)
+#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00)
+#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000)
+
+/*
+ * EDCA_AC0_CFG:
+ */
+#define EDCA_AC0_CFG 0x1300
+#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_AC1_CFG:
+ */
+#define EDCA_AC1_CFG 0x1304
+#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_AC2_CFG:
+ */
+#define EDCA_AC2_CFG 0x1308
+#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_AC3_CFG:
+ */
+#define EDCA_AC3_CFG 0x130c
+#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_TID_AC_MAP:
+ */
+#define EDCA_TID_AC_MAP 0x1310
+
+/*
+ * TX_PWR_CFG_0:
+ */
+#define TX_PWR_CFG_0 0x1314
+#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f)
+#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0)
+#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00)
+#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000)
+#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000)
+#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000)
+#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000)
+#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_1:
+ */
+#define TX_PWR_CFG_1 0x1318
+#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f)
+#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0)
+#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00)
+#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000)
+#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000)
+#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000)
+#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000)
+#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_2:
+ */
+#define TX_PWR_CFG_2 0x131c
+#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f)
+#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0)
+#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00)
+#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000)
+#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000)
+#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000)
+#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000)
+#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_3:
+ */
+#define TX_PWR_CFG_3 0x1320
+#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0)
+#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000)
+#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000)
+#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000)
+#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000)
+#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_4:
+ */
+#define TX_PWR_CFG_4 0x1324
+#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f)
+#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0)
+#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00)
+#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000)
+
+/*
+ * TX_PIN_CFG:
+ */
+#define TX_PIN_CFG 0x1328
+#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001)
+#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002)
+#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004)
+#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008)
+#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010)
+#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020)
+#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040)
+#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080)
+#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100)
+#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200)
+#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400)
+#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800)
+#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000)
+#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000)
+#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000)
+#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000)
+#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000)
+#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000)
+#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000)
+#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000)
+
+/*
+ * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz
+ */
+#define TX_BAND_CFG 0x132c
+#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001)
+#define TX_BAND_CFG_A FIELD32(0x00000002)
+#define TX_BAND_CFG_BG FIELD32(0x00000004)
+
+/*
+ * TX_SW_CFG0:
+ */
+#define TX_SW_CFG0 0x1330
+
+/*
+ * TX_SW_CFG1:
+ */
+#define TX_SW_CFG1 0x1334
+
+/*
+ * TX_SW_CFG2:
+ */
+#define TX_SW_CFG2 0x1338
+
+/*
+ * TXOP_THRES_CFG:
+ */
+#define TXOP_THRES_CFG 0x133c
+
+/*
+ * TXOP_CTRL_CFG:
+ */
+#define TXOP_CTRL_CFG 0x1340
+
+/*
+ * TX_RTS_CFG:
+ * RTS_THRES: unit:byte
+ * RTS_FBK_EN: enable rts rate fallback
+ */
+#define TX_RTS_CFG 0x1344
+#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff)
+#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00)
+#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000)
+
+/*
+ * TX_TIMEOUT_CFG:
+ * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us
+ * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure
+ * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation.
+ * it is recommended that:
+ * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT)
+ */
+#define TX_TIMEOUT_CFG 0x1348
+#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0)
+#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00)
+#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000)
+
+/*
+ * TX_RTY_CFG:
+ * SHORT_RTY_LIMIT: short retry limit
+ * LONG_RTY_LIMIT: long retry limit
+ * LONG_RTY_THRE: Long retry threshoold
+ * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode
+ * 0:expired by retry limit, 1: expired by mpdu life timer
+ * AGG_RTY_MODE: Aggregate MPDU retry mode
+ * 0:expired by retry limit, 1: expired by mpdu life timer
+ * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable
+ */
+#define TX_RTY_CFG 0x134c
+#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff)
+#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00)
+#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000)
+#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000)
+#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000)
+#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000)
+
+/*
+ * TX_LINK_CFG:
+ * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us
+ * MFB_ENABLE: TX apply remote MFB 1:enable
+ * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable
+ * 0: not apply remote remote unsolicit (MFS=7)
+ * TX_MRQ_EN: MCS request TX enable
+ * TX_RDG_EN: RDG TX enable
+ * TX_CF_ACK_EN: Piggyback CF-ACK enable
+ * REMOTE_MFB: remote MCS feedback
+ * REMOTE_MFS: remote MCS feedback sequence number
+ */
+#define TX_LINK_CFG 0x1350
+#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff)
+#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100)
+#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200)
+#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400)
+#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800)
+#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000)
+#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000)
+#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000)
+
+/*
+ * HT_FBK_CFG0:
+ */
+#define HT_FBK_CFG0 0x1354
+#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f)
+#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0)
+#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00)
+#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000)
+#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000)
+#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000)
+#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000)
+#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000)
+
+/*
+ * HT_FBK_CFG1:
+ */
+#define HT_FBK_CFG1 0x1358
+#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f)
+#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0)
+#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00)
+#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000)
+#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000)
+#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000)
+#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000)
+#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000)
+
+/*
+ * LG_FBK_CFG0:
+ */
+#define LG_FBK_CFG0 0x135c
+#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f)
+#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0)
+#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00)
+#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000)
+#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000)
+#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000)
+#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000)
+#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000)
+
+/*
+ * LG_FBK_CFG1:
+ */
+#define LG_FBK_CFG1 0x1360
+#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f)
+#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0)
+#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00)
+#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000)
+
+/*
+ * CCK_PROT_CFG: CCK Protection
+ * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd)
+ * PROTECT_CTRL: Protection control frame type for CCK TX
+ * 0:none, 1:RTS/CTS, 2:CTS-to-self
+ * PROTECT_NAV: TXOP protection type for CCK TX
+ * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect
+ * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow
+ * RTS_TH_EN: RTS threshold enable on CCK TX
+ */
+#define CCK_PROT_CFG 0x1364
+#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * OFDM_PROT_CFG: OFDM Protection
+ */
+#define OFDM_PROT_CFG 0x1368
+#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * MM20_PROT_CFG: MM20 Protection
+ */
+#define MM20_PROT_CFG 0x136c
+#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * MM40_PROT_CFG: MM40 Protection
+ */
+#define MM40_PROT_CFG 0x1370
+#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * GF20_PROT_CFG: GF20 Protection
+ */
+#define GF20_PROT_CFG 0x1374
+#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * GF40_PROT_CFG: GF40 Protection
+ */
+#define GF40_PROT_CFG 0x1378
+#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * EXP_CTS_TIME:
+ */
+#define EXP_CTS_TIME 0x137c
+
+/*
+ * EXP_ACK_TIME:
+ */
+#define EXP_ACK_TIME 0x1380
+
+/*
+ * RX_FILTER_CFG: RX configuration register.
+ */
+#define RX_FILTER_CFG 0x1400
+#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001)
+#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002)
+#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004)
+#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008)
+#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010)
+#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020)
+#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040)
+#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080)
+#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100)
+#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200)
+#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400)
+#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800)
+#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000)
+#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000)
+#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000)
+#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000)
+#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000)
+
+/*
+ * AUTO_RSP_CFG:
+ * AUTORESPONDER: 0: disable, 1: enable
+ * BAC_ACK_POLICY: 0:long, 1:short preamble
+ * CTS_40_MMODE: Response CTS 40MHz duplicate mode
+ * CTS_40_MREF: Response CTS 40MHz duplicate mode
+ * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble
+ * DUAL_CTS_EN: Power bit value in control frame
+ * ACK_CTS_PSM_BIT:Power bit value in control frame
+ */
+#define AUTO_RSP_CFG 0x1404
+#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001)
+#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002)
+#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004)
+#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008)
+#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010)
+#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040)
+#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080)
+
+/*
+ * LEGACY_BASIC_RATE:
+ */
+#define LEGACY_BASIC_RATE 0x1408
+
+/*
+ * HT_BASIC_RATE:
+ */
+#define HT_BASIC_RATE 0x140c
+
+/*
+ * HT_CTRL_CFG:
+ */
+#define HT_CTRL_CFG 0x1410
+
+/*
+ * SIFS_COST_CFG:
+ */
+#define SIFS_COST_CFG 0x1414
+
+/*
+ * RX_PARSER_CFG:
+ * Set NAV for all received frames
+ */
+#define RX_PARSER_CFG 0x1418
+
+/*
+ * TX_SEC_CNT0:
+ */
+#define TX_SEC_CNT0 0x1500
+
+/*
+ * RX_SEC_CNT0:
+ */
+#define RX_SEC_CNT0 0x1504
+
+/*
+ * CCMP_FC_MUTE:
+ */
+#define CCMP_FC_MUTE 0x1508
+
+/*
+ * TXOP_HLDR_ADDR0:
+ */
+#define TXOP_HLDR_ADDR0 0x1600
+
+/*
+ * TXOP_HLDR_ADDR1:
+ */
+#define TXOP_HLDR_ADDR1 0x1604
+
+/*
+ * TXOP_HLDR_ET:
+ */
+#define TXOP_HLDR_ET 0x1608
+
+/*
+ * QOS_CFPOLL_RA_DW0:
+ */
+#define QOS_CFPOLL_RA_DW0 0x160c
+
+/*
+ * QOS_CFPOLL_RA_DW1:
+ */
+#define QOS_CFPOLL_RA_DW1 0x1610
+
+/*
+ * QOS_CFPOLL_QC:
+ */
+#define QOS_CFPOLL_QC 0x1614
+
+/*
+ * RX_STA_CNT0: RX PLCP error count & RX CRC error count
+ */
+#define RX_STA_CNT0 0x1700
+#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff)
+#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000)
+
+/*
+ * RX_STA_CNT1: RX False CCA count & RX LONG frame count
+ */
+#define RX_STA_CNT1 0x1704
+#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff)
+#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000)
+
+/*
+ * RX_STA_CNT2:
+ */
+#define RX_STA_CNT2 0x1708
+#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff)
+#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000)
+
+/*
+ * TX_STA_CNT0: TX Beacon count
+ */
+#define TX_STA_CNT0 0x170c
+#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff)
+#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_STA_CNT1: TX tx count
+ */
+#define TX_STA_CNT1 0x1710
+#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff)
+#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000)
+
+/*
+ * TX_STA_CNT2: TX tx count
+ */
+#define TX_STA_CNT2 0x1714
+#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff)
+#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_STA_FIFO: TX Result for specific PID status fifo register
+ */
+#define TX_STA_FIFO 0x1718
+#define TX_STA_FIFO_VALID FIELD32(0x00000001)
+#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e)
+#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020)
+#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040)
+#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080)
+#define TX_STA_FIFO_WCID FIELD32(0x0000ff00)
+#define TX_STA_FIFO_MCS FIELD32(0x007f0000)
+#define TX_STA_FIFO_PHYMODE FIELD32(0xc0000000)
+
+/*
+ * TX_AGG_CNT: Debug counter
+ */
+#define TX_AGG_CNT 0x171c
+#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT0:
+ */
+#define TX_AGG_CNT0 0x1720
+#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT1:
+ */
+#define TX_AGG_CNT1 0x1724
+#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT2:
+ */
+#define TX_AGG_CNT2 0x1728
+#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT3:
+ */
+#define TX_AGG_CNT3 0x172c
+#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT4:
+ */
+#define TX_AGG_CNT4 0x1730
+#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT5:
+ */
+#define TX_AGG_CNT5 0x1734
+#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT6:
+ */
+#define TX_AGG_CNT6 0x1738
+#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT7:
+ */
+#define TX_AGG_CNT7 0x173c
+#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000)
+
+/*
+ * MPDU_DENSITY_CNT:
+ * TX_ZERO_DEL: TX zero length delimiter count
+ * RX_ZERO_DEL: RX zero length delimiter count
+ */
+#define MPDU_DENSITY_CNT 0x1740
+#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff)
+#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000)
+
+/*
+ * Security key table memory.
+ * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry
+ * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry
+ * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry
+ * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry
+ * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry
+ * SHARED_KEY_MODE_BASE: 4 bits * 32-entry
+ */
+#define MAC_WCID_BASE 0x1800
+#define PAIRWISE_KEY_TABLE_BASE 0x4000
+#define MAC_IVEIV_TABLE_BASE 0x6000
+#define MAC_WCID_ATTRIBUTE_BASE 0x6800
+#define SHARED_KEY_TABLE_BASE 0x6c00
+#define SHARED_KEY_MODE_BASE 0x7000
+
+#define MAC_WCID_ENTRY(__idx) \
+ ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) )
+#define PAIRWISE_KEY_ENTRY(__idx) \
+ ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
+#define MAC_IVEIV_ENTRY(__idx) \
+ ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) )
+#define MAC_WCID_ATTR_ENTRY(__idx) \
+ ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) )
+#define SHARED_KEY_ENTRY(__idx) \
+ ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
+#define SHARED_KEY_MODE_ENTRY(__idx) \
+ ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) )
+
+struct mac_wcid_entry {
+ u8 mac[6];
+ u8 reserved[2];
+} __attribute__ ((packed));
+
+struct hw_key_entry {
+ u8 key[16];
+ u8 tx_mic[8];
+ u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct mac_iveiv_entry {
+ u8 iv[8];
+} __attribute__ ((packed));
+
+/*
+ * MAC_WCID_ATTRIBUTE:
+ */
+#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001)
+#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e)
+#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070)
+#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380)
+
+/*
+ * SHARED_KEY_MODE:
+ */
+#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007)
+#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070)
+#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700)
+#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000)
+#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000)
+#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000)
+#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000)
+#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000)
+
+/*
+ * HOST-MCU communication
+ */
+
+/*
+ * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
+ */
+#define H2M_MAILBOX_CSR 0x7010
+#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff)
+#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00)
+#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000)
+#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000)
+
+/*
+ * H2M_MAILBOX_CID:
+ */
+#define H2M_MAILBOX_CID 0x7014
+#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff)
+#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00)
+#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000)
+#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000)
+
+/*
+ * H2M_MAILBOX_STATUS:
+ */
+#define H2M_MAILBOX_STATUS 0x701c
+
+/*
+ * H2M_INT_SRC:
+ */
+#define H2M_INT_SRC 0x7024
+
+/*
+ * H2M_BBP_AGENT:
+ */
+#define H2M_BBP_AGENT 0x7028
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE FIELD8(0x1f)
+#define MCU_LEDCS_POLARITY FIELD8(0x01)
+
+/*
+ * HW_CS_CTS_BASE:
+ * Carrier-sense CTS frame base address.
+ * It's where mac stores carrier-sense frame for carrier-sense function.
+ */
+#define HW_CS_CTS_BASE 0x7700
+
+/*
+ * HW_DFS_CTS_BASE:
+ * FS CTS frame base address. It's where mac stores CTS frame for DFS.
+ */
+#define HW_DFS_CTS_BASE 0x7780
+
+/*
+ * TXRX control registers - base address 0x3000
+ */
+
+/*
+ * TXRX_CSR1:
+ * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first..
+ */
+#define TXRX_CSR1 0x77d0
+
+/*
+ * HW_DEBUG_SETTING_BASE:
+ * since NULL frame won't be that long (256 byte)
+ * We steal 16 tail bytes to save debugging settings
+ */
+#define HW_DEBUG_SETTING_BASE 0x77f0
+#define HW_DEBUG_SETTING_BASE2 0x7770
+
+/*
+ * HW_BEACON_BASE
+ * In order to support maximum 8 MBSS and its maximum length
+ * is 512 bytes for each beacon
+ * Three section discontinue memory segments will be used.
+ * 1. The original region for BCN 0~3
+ * 2. Extract memory from FCE table for BCN 4~5
+ * 3. Extract memory from Pair-wise key table for BCN 6~7
+ * It occupied those memory of wcid 238~253 for BCN 6
+ * and wcid 222~237 for BCN 7
+ *
+ * IMPORTANT NOTE: Not sure why legacy driver does this,
+ * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6.
+ */
+#define HW_BEACON_BASE0 0x7800
+#define HW_BEACON_BASE1 0x7a00
+#define HW_BEACON_BASE2 0x7c00
+#define HW_BEACON_BASE3 0x7e00
+#define HW_BEACON_BASE4 0x7200
+#define HW_BEACON_BASE5 0x7400
+#define HW_BEACON_BASE6 0x5dc0
+#define HW_BEACON_BASE7 0x5bc0
+
+#define HW_BEACON_OFFSET(__index) \
+ ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \
+ (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \
+ (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) )
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2860 "rt2860.bin"
+#define FIRMWARE_IMAGE_BASE 0x2000
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * BBP 1: TX Antenna
+ */
+#define BBP1_TX_POWER FIELD8(0x07)
+#define BBP1_TX_ANTENNA FIELD8(0x18)
+
+/*
+ * BBP 3: RX Antenna
+ */
+#define BBP3_RX_ANTENNA FIELD8(0x18)
+#define BBP3_HT40_PLUS FIELD8(0x20)
+
+/*
+ * BBP 4: Bandwidth
+ */
+#define BBP4_TX_BF FIELD8(0x01)
+#define BBP4_BANDWIDTH FIELD8(0x18)
+
+/*
+ * RFCSR registers
+ * The wordsize of the RFCSR is 8 bits.
+ */
+
+/*
+ * RFCSR 6:
+ */
+#define RFCSR6_R FIELD8(0x03)
+
+/*
+ * RFCSR 7:
+ */
+#define RFCSR7_RF_TUNING FIELD8(0x01)
+
+/*
+ * RFCSR 12:
+ */
+#define RFCSR12_TX_POWER FIELD8(0x1f)
+
+/*
+ * RFCSR 22:
+ */
+#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01)
+
+/*
+ * RFCSR 23:
+ */
+#define RFCSR23_FREQ_OFFSET FIELD8(0x7f)
+
+/*
+ * RFCSR 30:
+ */
+#define RFCSR30_RF_CALIBRATION FIELD8(0x80)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 2
+ */
+#define RF2_ANTENNA_RX2 FIELD32(0x00000040)
+#define RF2_ANTENNA_TX1 FIELD32(0x00004000)
+#define RF2_ANTENNA_RX1 FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER_G FIELD32(0x00003e00)
+#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200)
+#define RF3_TXPOWER_A FIELD32(0x00003c00)
+
+/*
+ * RF 4
+ */
+#define RF4_TXPOWER_G FIELD32(0x000007c0)
+#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040)
+#define RF4_TXPOWER_A FIELD32(0x00000780)
+#define RF4_FREQ_OFFSET FIELD32(0x001f8000)
+#define RF4_HT40 FIELD32(0x00200000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * EEPROM Version
+ */
+#define EEPROM_VERSION 0x0001
+#define EEPROM_VERSION_FAE FIELD16(0x00ff)
+#define EEPROM_VERSION_VERSION FIELD16(0xff00)
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM ANTENNA config
+ * RXPATH: 1: 1R, 2: 2R, 3: 3R
+ * TXPATH: 1: 1T, 2: 2T
+ */
+#define EEPROM_ANTENNA 0x001a
+#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f)
+#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00)
+
+/*
+ * EEPROM NIC config
+ * CARDBUS_ACCEL: 0 - enable, 1 - disable
+ */
+#define EEPROM_NIC 0x001b
+#define EEPROM_NIC_HW_RADIO FIELD16(0x0001)
+#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002)
+#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004)
+#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008)
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010)
+#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020)
+#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040)
+#define EEPROM_NIC_WPS_PBC FIELD16(0x0080)
+#define EEPROM_NIC_BW40M_BG FIELD16(0x0100)
+#define EEPROM_NIC_BW40M_A FIELD16(0x0200)
+
+/*
+ * EEPROM frequency
+ */
+#define EEPROM_FREQ 0x001d
+#define EEPROM_FREQ_OFFSET FIELD16(0x00ff)
+#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00)
+#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000)
+
+/*
+ * EEPROM LED
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED1 0x001e
+#define EEPROM_LED2 0x001f
+#define EEPROM_LED3 0x0020
+#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
+
+/*
+ * EEPROM LNA
+ */
+#define EEPROM_LNA 0x0022
+#define EEPROM_LNA_BG FIELD16(0x00ff)
+#define EEPROM_LNA_A0 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI BG offset
+ */
+#define EEPROM_RSSI_BG 0x0023
+#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff)
+#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI BG2 offset
+ */
+#define EEPROM_RSSI_BG2 0x0024
+#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff)
+#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI A offset
+ */
+#define EEPROM_RSSI_A 0x0025
+#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff)
+#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI A2 offset
+ */
+#define EEPROM_RSSI_A2 0x0026
+#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff)
+#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00)
+
+/*
+ * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
+ * This is delta in 40MHZ.
+ * VALUE: Tx Power dalta value (MAX=4)
+ * TYPE: 1: Plus the delta value, 0: minus the delta value
+ * TXPOWER: Enable:
+ */
+#define EEPROM_TXPOWER_DELTA 0x0028
+#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f)
+#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040)
+#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080)
+
+/*
+ * EEPROM TXPOWER 802.11BG
+ */
+#define EEPROM_TXPOWER_BG1 0x0029
+#define EEPROM_TXPOWER_BG2 0x0030
+#define EEPROM_TXPOWER_BG_SIZE 7
+#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A1 0x003c
+#define EEPROM_TXPOWER_A2 0x0053
+#define EEPROM_TXPOWER_A_SIZE 6
+#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
+
+/*
+ * EEPROM TXpower byrate: 20MHZ power
+ */
+#define EEPROM_TXPOWER_BYRATE 0x006f
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0078
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * MCU mailbox commands.
+ */
+#define MCU_SLEEP 0x30
+#define MCU_WAKEUP 0x31
+#define MCU_RADIO_OFF 0x35
+#define MCU_CURRENT 0x36
+#define MCU_LED 0x50
+#define MCU_LED_STRENGTH 0x51
+#define MCU_LED_1 0x52
+#define MCU_LED_2 0x53
+#define MCU_LED_3 0x54
+#define MCU_RADAR 0x60
+#define MCU_BOOT_SIGNAL 0x72
+#define MCU_BBP_SIGNAL 0x80
+#define MCU_POWER_SAVE 0x83
+
+/*
+ * MCU mailbox tokens
+ */
+#define TOKEN_WAKUP 3
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 4 * sizeof(__le32) )
+#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) )
+#define RXD_DESC_SIZE ( 4 * sizeof(__le32) )
+#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_SD_PTR0 FIELD32(0xffffffff)
+
+/*
+ * Word1
+ */
+#define TXD_W1_SD_LEN1 FIELD32(0x00003fff)
+#define TXD_W1_LAST_SEC1 FIELD32(0x00004000)
+#define TXD_W1_BURST FIELD32(0x00008000)
+#define TXD_W1_SD_LEN0 FIELD32(0x3fff0000)
+#define TXD_W1_LAST_SEC0 FIELD32(0x40000000)
+#define TXD_W1_DMA_DONE FIELD32(0x80000000)
+
+/*
+ * Word2
+ */
+#define TXD_W2_SD_PTR1 FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI
+ * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler.
+ * 0:MGMT, 1:HCCA 2:EDCA
+ */
+#define TXD_W3_WIV FIELD32(0x01000000)
+#define TXD_W3_QSEL FIELD32(0x06000000)
+#define TXD_W3_TCO FIELD32(0x20000000)
+#define TXD_W3_UCO FIELD32(0x40000000)
+#define TXD_W3_ICO FIELD32(0x80000000)
+
+/*
+ * TX WI structure
+ */
+
+/*
+ * Word0
+ * FRAG: 1 To inform TKIP engine this is a fragment.
+ * MIMO_PS: The remote peer is in dynamic MIMO-PS mode
+ * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs
+ * BW: Channel bandwidth 20MHz or 40 MHz
+ * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED
+ */
+#define TXWI_W0_FRAG FIELD32(0x00000001)
+#define TXWI_W0_MIMO_PS FIELD32(0x00000002)
+#define TXWI_W0_CF_ACK FIELD32(0x00000004)
+#define TXWI_W0_TS FIELD32(0x00000008)
+#define TXWI_W0_AMPDU FIELD32(0x00000010)
+#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0)
+#define TXWI_W0_TX_OP FIELD32(0x00000300)
+#define TXWI_W0_MCS FIELD32(0x007f0000)
+#define TXWI_W0_BW FIELD32(0x00800000)
+#define TXWI_W0_SHORT_GI FIELD32(0x01000000)
+#define TXWI_W0_STBC FIELD32(0x06000000)
+#define TXWI_W0_IFS FIELD32(0x08000000)
+#define TXWI_W0_PHYMODE FIELD32(0xc0000000)
+
+/*
+ * Word1
+ */
+#define TXWI_W1_ACK FIELD32(0x00000001)
+#define TXWI_W1_NSEQ FIELD32(0x00000002)
+#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc)
+#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00)
+#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
+#define TXWI_W1_PACKETID FIELD32(0xf0000000)
+
+/*
+ * Word2
+ */
+#define TXWI_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ */
+#define TXWI_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_SDP0 FIELD32(0xffffffff)
+
+/*
+ * Word1
+ */
+#define RXD_W1_SDL1 FIELD32(0x00003fff)
+#define RXD_W1_SDL0 FIELD32(0x3fff0000)
+#define RXD_W1_LS0 FIELD32(0x40000000)
+#define RXD_W1_DMA_DONE FIELD32(0x80000000)
+
+/*
+ * Word2
+ */
+#define RXD_W2_SDP1 FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * AMSDU: RX with 802.3 header, not 802.11 header.
+ * DECRYPTED: This frame is being decrypted.
+ */
+#define RXD_W3_BA FIELD32(0x00000001)
+#define RXD_W3_DATA FIELD32(0x00000002)
+#define RXD_W3_NULLDATA FIELD32(0x00000004)
+#define RXD_W3_FRAG FIELD32(0x00000008)
+#define RXD_W3_UNICAST_TO_ME FIELD32(0x00000010)
+#define RXD_W3_MULTICAST FIELD32(0x00000020)
+#define RXD_W3_BROADCAST FIELD32(0x00000040)
+#define RXD_W3_MY_BSS FIELD32(0x00000080)
+#define RXD_W3_CRC_ERROR FIELD32(0x00000100)
+#define RXD_W3_CIPHER_ERROR FIELD32(0x00000600)
+#define RXD_W3_AMSDU FIELD32(0x00000800)
+#define RXD_W3_HTC FIELD32(0x00001000)
+#define RXD_W3_RSSI FIELD32(0x00002000)
+#define RXD_W3_L2PAD FIELD32(0x00004000)
+#define RXD_W3_AMPDU FIELD32(0x00008000)
+#define RXD_W3_DECRYPTED FIELD32(0x00010000)
+#define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000)
+#define RXD_W3_PLCP_RSSI FIELD32(0x00040000)
+
+/*
+ * RX WI structure
+ */
+
+/*
+ * Word0
+ */
+#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff)
+#define RXWI_W0_KEY_INDEX FIELD32(0x00000300)
+#define RXWI_W0_BSSID FIELD32(0x00001c00)
+#define RXWI_W0_UDF FIELD32(0x0000e000)
+#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
+#define RXWI_W0_TID FIELD32(0xf0000000)
+
+/*
+ * Word1
+ */
+#define RXWI_W1_FRAG FIELD32(0x0000000f)
+#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0)
+#define RXWI_W1_MCS FIELD32(0x007f0000)
+#define RXWI_W1_BW FIELD32(0x00800000)
+#define RXWI_W1_SHORT_GI FIELD32(0x01000000)
+#define RXWI_W1_STBC FIELD32(0x06000000)
+#define RXWI_W1_PHYMODE FIELD32(0xc0000000)
+
+/*
+ * Word2
+ */
+#define RXWI_W2_RSSI0 FIELD32(0x000000ff)
+#define RXWI_W2_RSSI1 FIELD32(0x0000ff00)
+#define RXWI_W2_RSSI2 FIELD32(0x00ff0000)
+
+/*
+ * Word3
+ */
+#define RXWI_W3_SNR0 FIELD32(0x000000ff)
+#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
+
+/*
+ * Macros for converting txpower from EEPROM to mac80211 value
+ * and from mac80211 value to register value.
+ */
+#define MIN_G_TXPOWER 0
+#define MIN_A_TXPOWER -7
+#define MAX_G_TXPOWER 31
+#define MAX_A_TXPOWER 15
+#define DEFAULT_TXPOWER 5
+
+#define TXPOWER_G_FROM_DEV(__txpower) \
+ ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_G_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER)
+
+#define TXPOWER_A_FROM_DEV(__txpower) \
+ ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_A_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER)
+
+#endif /* RT2800PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 27bc6b7fbfd..196de8ab815 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -158,6 +158,13 @@ struct rt2x00_chip {
#define RT2561 0x0302
#define RT2661 0x0401
#define RT2571 0x1300
+#define RT2860 0x0601 /* 2.4GHz PCI/CB */
+#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */
+#define RT2890 0x0701 /* 2.4GHz PCIe */
+#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */
+#define RT2880 0x2880 /* WSOC */
+#define RT3052 0x3052 /* WSOC */
+#define RT3090 0x3090 /* 2.4GHz PCIe */
#define RT2870 0x1600
u16 rf;
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c
new file mode 100644
index 00000000000..539568c4895
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.c
@@ -0,0 +1,159 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00soc
+ Abstract: rt2x00 generic soc device routines.
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "rt2x00.h"
+#include "rt2x00soc.h"
+
+static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rf);
+ rt2x00dev->rf = NULL;
+
+ kfree(rt2x00dev->eeprom);
+ rt2x00dev->eeprom = NULL;
+}
+
+static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+ struct platform_device *pdev = to_platform_device(rt2x00dev->dev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ rt2x00dev->csr.base = (void __iomem *)KSEG1ADDR(res->start);
+ if (!rt2x00dev->csr.base)
+ goto exit;
+
+ rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+ if (!rt2x00dev->eeprom)
+ goto exit;
+
+ rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+ if (!rt2x00dev->rf)
+ goto exit;
+
+ return 0;
+
+exit:
+ ERROR_PROBE("Failed to allocate registers.\n");
+ rt2x00soc_free_reg(rt2x00dev);
+
+ return -ENOMEM;
+}
+
+int rt2x00soc_probe(struct platform_device *pdev,
+ const unsigned short chipset,
+ const struct rt2x00_ops *ops)
+{
+ struct ieee80211_hw *hw;
+ struct rt2x00_dev *rt2x00dev;
+ int retval;
+
+ hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+ if (!hw) {
+ ERROR_PROBE("Failed to allocate hardware.\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, hw);
+
+ rt2x00dev = hw->priv;
+ rt2x00dev->dev = &pdev->dev;
+ rt2x00dev->ops = ops;
+ rt2x00dev->hw = hw;
+ rt2x00dev->irq = platform_get_irq(pdev, 0);
+ rt2x00dev->name = pdev->dev.driver->name;
+
+ rt2x00_set_chip_rt(rt2x00dev, chipset);
+
+ retval = rt2x00soc_alloc_reg(rt2x00dev);
+ if (retval)
+ goto exit_free_device;
+
+ retval = rt2x00lib_probe_dev(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00soc_free_reg(rt2x00dev);
+
+exit_free_device:
+ ieee80211_free_hw(hw);
+
+ return retval;
+}
+
+int rt2x00soc_remove(struct platform_device *pdev)
+{
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Free all allocated data.
+ */
+ rt2x00lib_remove_dev(rt2x00dev);
+ rt2x00soc_free_reg(rt2x00dev);
+ ieee80211_free_hw(hw);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00soc_remove);
+
+#ifdef CONFIG_PM
+int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ return rt2x00lib_suspend(rt2x00dev, state);
+}
+EXPORT_SYMBOL_GPL(rt2x00soc_suspend);
+
+int rt2x00soc_resume(struct platform_device *pdev)
+{
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ return rt2x00lib_resume(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00soc_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00soc module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 soc library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h
new file mode 100644
index 00000000000..5cf114ac2b9
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ 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; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00soc
+ Abstract: Data structures for the rt2x00soc module.
+ */
+
+#ifndef RT2X00SOC_H
+#define RT2X00SOC_H
+
+#define KSEG1ADDR(__ptr) __ptr
+
+#define __rt2x00soc_probe(__chipset, __ops) \
+static int __rt2x00soc_probe(struct platform_device *pdev) \
+{ \
+ return rt2x00soc_probe(pdev, (__chipset), (__ops)); \
+}
+
+/*
+ * SoC driver handlers.
+ */
+int rt2x00soc_probe(struct platform_device *pdev,
+ const unsigned short chipset,
+ const struct rt2x00_ops *ops);
+int rt2x00soc_remove(struct platform_device *pdev);
+#ifdef CONFIG_PM
+int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state);
+int rt2x00soc_resume(struct platform_device *pdev);
+#else
+#define rt2x00soc_suspend NULL
+#define rt2x00soc_resume NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00SOC_H */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index ea6a87c1931..698aade79d4 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -106,6 +106,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE";
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/rcupdate.h>
+#include <linux/compat.h>
#include <net/arp.h>
#include <net/net_namespace.h>
@@ -2725,6 +2726,19 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file,
return 0;
}
+#ifdef CONFIG_COMPAT
+static long strip_compat_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case SIOCGIFNAME:
+ case SIOCSIFHWADDR:
+ return strip_ioctl(tty, file, cmd,
+ (unsigned long)compat_ptr(arg));
+ }
+ return -ENOIOCTLCMD;
+}
+#endif
/************************************************************************/
/* Initialization */
@@ -2736,6 +2750,9 @@ static struct tty_ldisc_ops strip_ldisc = {
.open = strip_open,
.close = strip_close,
.ioctl = strip_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = strip_compat_ioctl,
+#endif
.receive_buf = strip_receive_buf,
.write_wakeup = strip_write_some_more,
};
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 1103256ad98..48b0bfd6c55 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -183,8 +183,11 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
wl->chip_id);
break;
- case CHIP_ID_1251_PG10:
case CHIP_ID_1251_PG11:
+ wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)",
+ wl->chip_id);
+ break;
+ case CHIP_ID_1251_PG10:
default:
wl1251_error("unsupported chip id: 0x%x", wl->chip_id);
ret = -ENODEV;
@@ -1426,4 +1429,4 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw);
MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
-MODULE_ALIAS("spi:wl12xx");
+MODULE_ALIAS("spi:wl1251");
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
deleted file mode 100644
index ee36695e134..00000000000
--- a/drivers/net/wireless/wl12xx/wl1251_netlink.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This file is part of wl1251
- *
- * Copyright (C) 2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __WL1251_NETLINK_H__
-#define __WL1251_NETLINK_H__
-
-int wl1251_nl_register(void);
-void wl1251_nl_unregister(void);
-
-#endif /* __WL1251_NETLINK_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 17c54b59ef8..601fe0d6782 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -153,7 +153,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
beacon ? "beacon" : "");
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
- ieee80211_rx(wl->hw, skb);
+ ieee80211_rx_ni(wl->hw, skb);
}
static void wl1251_rx_ack(struct wl1251 *wl)
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index 14eff2b3d4c..2cf8a2169d4 100644
--- a/drivers/net/wireless/wl12xx/wl1251_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -307,7 +307,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi)
static struct spi_driver wl1251_spi_driver = {
.driver = {
- .name = "wl12xx",
+ .name = "wl1251",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 55818f94017..566f1521ec2 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -32,6 +32,8 @@
#include <linux/bitops.h>
#include <net/mac80211.h>
+#include "wl1271_conf.h"
+
#define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": "
@@ -97,21 +99,42 @@ enum {
} while (0)
#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN)
+ CFG_BSSID_FILTER_EN | \
+ CFG_MC_FILTER_EN)
#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
+#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL)
+
#define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin"
-#define WL1271_BUSY_WORD_LEN 8
+/*
+ * Enable/disable 802.11a support for WL1273
+ */
+#undef WL1271_80211A_ENABLED
+
+/*
+ * FIXME: for the wl1271, a busy word count of 1 here will result in a more
+ * optimal SPI interface. There is some SPI bug however, causing RXS time outs
+ * with this mode occasionally on boot, so lets have three for now. A value of
+ * three should make sure, that the chipset will always be ready, though this
+ * will impact throughput and latencies slightly.
+ */
+#define WL1271_BUSY_WORD_CNT 3
+#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
#define WL1271_ELP_HW_STATE_ASLEEP 0
#define WL1271_ELP_HW_STATE_IRQ 1
+#define WL1271_DEFAULT_BEACON_INT 100
+#define WL1271_DEFAULT_DTIM_PERIOD 1
+
+#define ACX_TX_DESCRIPTORS 32
+
enum wl1271_state {
WL1271_STATE_OFF,
WL1271_STATE_ON,
@@ -134,6 +157,8 @@ struct wl1271_partition {
struct wl1271_partition_set {
struct wl1271_partition mem;
struct wl1271_partition reg;
+ struct wl1271_partition mem2;
+ struct wl1271_partition mem3;
};
struct wl1271;
@@ -258,15 +283,15 @@ struct wl1271_debugfs {
/* FW status registers */
struct wl1271_fw_status {
- u32 intr;
+ __le32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
u8 reserved;
u8 tx_results_counter;
- u32 rx_pkt_descs[NUM_RX_PKT_DESC];
- u32 tx_released_blks[NUM_TX_QUEUES];
- u32 fw_localtime;
- u32 padding[2];
+ __le32 rx_pkt_descs[NUM_RX_PKT_DESC];
+ __le32 tx_released_blks[NUM_TX_QUEUES];
+ __le32 fw_localtime;
+ __le32 padding[2];
} __attribute__ ((packed));
struct wl1271_rx_mem_pool_addr {
@@ -274,6 +299,15 @@ struct wl1271_rx_mem_pool_addr {
u32 addr_extra;
};
+struct wl1271_scan {
+ u8 state;
+ u8 ssid[IW_ESSID_MAX_SIZE+1];
+ size_t ssid_len;
+ u8 active;
+ u8 high_prio;
+ u8 probe_requests;
+};
+
struct wl1271 {
struct ieee80211_hw *hw;
bool mac80211_registered;
@@ -288,10 +322,7 @@ struct wl1271 {
enum wl1271_state state;
struct mutex mutex;
- int physical_mem_addr;
- int physical_reg_addr;
- int virtual_mem_addr;
- int virtual_reg_addr;
+ struct wl1271_partition_set part;
struct wl1271_chip chip;
@@ -308,7 +339,6 @@ struct wl1271 {
u8 bss_type;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
- u8 listen_int;
int channel;
struct wl1271_acx_mem_map *target_mem_map;
@@ -332,10 +362,14 @@ struct wl1271 {
bool tx_queue_stopped;
struct work_struct tx_work;
- struct work_struct filter_work;
/* Pending TX frames */
- struct sk_buff *tx_frames[16];
+ struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
+
+ /* Security sequence number counters */
+ u8 tx_security_last_seq;
+ u16 tx_security_seq_16;
+ u32 tx_security_seq_32;
/* FW Rx counter */
u32 rx_counter;
@@ -354,10 +388,17 @@ struct wl1271 {
/* Are we currently scanning */
bool scanning;
+ struct wl1271_scan scan;
/* Our association ID */
u16 aid;
+ /* currently configured rate set */
+ u32 basic_rate_set;
+
+ /* The current band */
+ enum ieee80211_band band;
+
/* Default key (for WEP) */
u32 default_key;
@@ -368,6 +409,7 @@ struct wl1271 {
bool elp;
struct completion *elp_compl;
+ struct delayed_work elp_work;
/* we can be in psm, but not in elp, we have to differentiate */
bool psm;
@@ -383,11 +425,20 @@ struct wl1271 {
u32 buffer_32;
u32 buffer_cmd;
- u8 buffer_busyword[WL1271_BUSY_WORD_LEN];
- struct wl1271_rx_descriptor *rx_descriptor;
+ u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
struct wl1271_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
+
+ struct ieee80211_vif *vif;
+
+ /* Used for a workaround to send disconnect before rejoining */
+ bool joined;
+
+ /* Current chipset configuration */
+ struct conf_drv_settings conf;
+
+ struct list_head list;
};
int wl1271_plt_start(struct wl1271 *wl);
@@ -404,4 +455,13 @@ int wl1271_plt_stop(struct wl1271 *wl);
/* WL1271 needs a 200ms sleep after power on */
#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
+static inline bool wl1271_11a_enabled(void)
+{
+#ifdef WL1271_80211A_ENABLED
+ return true;
+#else
+ return false;
+#endif
+}
+
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index f622a409261..bf5a8680a46 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -34,8 +34,7 @@
#include "wl1271_spi.h"
#include "wl1271_ps.h"
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
- u8 listen_interval)
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
{
struct acx_wake_up_condition *wake_up;
int ret;
@@ -48,8 +47,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
goto out;
}
- wake_up->wake_up_event = wake_up_event;
- wake_up->listen_interval = listen_interval;
+ wake_up->wake_up_event = wl->conf.conn.wake_up_event;
+ wake_up->listen_interval = wl->conf.conn.listen_interval;
ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
wake_up, sizeof(*wake_up));
@@ -137,7 +136,12 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
goto out;
}
- acx->current_tx_power = power * 10;
+ /*
+ * FIXME: This is a workaround needed while we don't the correct
+ * calibration, to avoid distortions
+ */
+ /* acx->current_tx_power = power * 10; */
+ acx->current_tx_power = 70;
ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
if (ret < 0) {
@@ -193,7 +197,7 @@ int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map,
return 0;
}
-int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time)
+int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl)
{
struct acx_rx_msdu_lifetime *acx;
int ret;
@@ -206,7 +210,7 @@ int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time)
goto out;
}
- acx->lifetime = life_time;
+ acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time);
ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
acx, sizeof(*acx));
if (ret < 0) {
@@ -232,8 +236,8 @@ int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter)
goto out;
}
- rx_config->config_options = config;
- rx_config->filter_options = filter;
+ rx_config->config_options = cpu_to_le32(config);
+ rx_config->filter_options = cpu_to_le32(filter);
ret = wl1271_cmd_configure(wl, ACX_RX_CFG,
rx_config, sizeof(*rx_config));
@@ -260,7 +264,7 @@ int wl1271_acx_pd_threshold(struct wl1271 *wl)
goto out;
}
- /* FIXME: threshold value not set */
+ pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold);
ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
if (ret < 0) {
@@ -300,7 +304,8 @@ out:
return ret;
}
-int wl1271_acx_group_address_tbl(struct wl1271 *wl)
+int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
+ void *mc_list, u32 mc_list_len)
{
struct acx_dot11_grp_addr_tbl *acx;
int ret;
@@ -314,9 +319,9 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl)
}
/* MAC filtering */
- acx->enabled = 0;
- acx->num_groups = 0;
- memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+ acx->enabled = enable;
+ acx->num_groups = mc_list_len;
+ memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
acx, sizeof(*acx));
@@ -343,8 +348,8 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl)
wl1271_debug(DEBUG_ACX, "acx service period timeout");
- rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
- rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF;
+ rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout);
+ rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout);
ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
rx_timeout, sizeof(*rx_timeout));
@@ -372,7 +377,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
goto out;
}
- rts->threshold = rts_threshold;
+ rts->threshold = cpu_to_le16(rts_threshold);
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
if (ret < 0) {
@@ -385,20 +390,29 @@ out:
return ret;
}
-int wl1271_acx_beacon_filter_opt(struct wl1271 *wl)
+int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
{
- struct acx_beacon_filter_option *beacon_filter;
- int ret;
+ struct acx_beacon_filter_option *beacon_filter = NULL;
+ int ret = 0;
wl1271_debug(DEBUG_ACX, "acx beacon filter opt");
+ if (enable_filter &&
+ wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED)
+ goto out;
+
beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
if (!beacon_filter) {
ret = -ENOMEM;
goto out;
}
- beacon_filter->enable = 0;
+ beacon_filter->enable = enable_filter;
+
+ /*
+ * When set to zero, and the filter is enabled, beacons
+ * without the unicast TIM bit set are dropped.
+ */
beacon_filter->max_num_beacons = 0;
ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
@@ -416,7 +430,9 @@ out:
int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
{
struct acx_beacon_filter_ie_table *ie_table;
+ int i, idx = 0;
int ret;
+ bool vendor_spec = false;
wl1271_debug(DEBUG_ACX, "acx beacon filter table");
@@ -426,8 +442,32 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
goto out;
}
+ /* configure default beacon pass-through rules */
ie_table->num_ie = 0;
- memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+ for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) {
+ struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]);
+ ie_table->table[idx++] = r->ie;
+ ie_table->table[idx++] = r->rule;
+
+ if (r->ie == WLAN_EID_VENDOR_SPECIFIC) {
+ /* only one vendor specific ie allowed */
+ if (vendor_spec)
+ continue;
+
+ /* for vendor specific rules configure the
+ additional fields */
+ memcpy(&(ie_table->table[idx]), r->oui,
+ CONF_BCN_IE_OUI_LEN);
+ idx += CONF_BCN_IE_OUI_LEN;
+ ie_table->table[idx++] = r->type;
+ memcpy(&(ie_table->table[idx]), r->version,
+ CONF_BCN_IE_VER_LEN);
+ idx += CONF_BCN_IE_VER_LEN;
+ vendor_spec = true;
+ }
+
+ ie_table->num_ie++;
+ }
ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
ie_table, sizeof(*ie_table));
@@ -441,6 +481,36 @@ out:
return ret;
}
+int wl1271_acx_conn_monit_params(struct wl1271 *wl)
+{
+ struct acx_conn_monit_params *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx connection monitor parameters");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->synch_fail_thold = cpu_to_le32(wl->conf.conn.synch_fail_thold);
+ acx->bss_lose_timeout = cpu_to_le32(wl->conf.conn.bss_lose_timeout);
+
+ ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("failed to set connection monitor "
+ "parameters: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+
int wl1271_acx_sg_enable(struct wl1271 *wl)
{
struct acx_bt_wlan_coex *pta;
@@ -470,6 +540,7 @@ out:
int wl1271_acx_sg_cfg(struct wl1271 *wl)
{
struct acx_bt_wlan_coex_param *param;
+ struct conf_sg_settings *c = &wl->conf.sg;
int ret;
wl1271_debug(DEBUG_ACX, "acx sg cfg");
@@ -481,34 +552,19 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
}
/* BT-WLAN coext parameters */
- param->min_rate = RATE_INDEX_24MBPS;
- param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
- param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
- param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
- param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
- param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
- param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
- param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
- param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
- param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
- param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
- param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
- param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
- param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
- param->antenna_type = PTA_ANTENNA_TYPE_DEF;
- param->signal_type = PTA_SIGNALING_TYPE_DEF;
- param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
- param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
- param->max_cts = PTA_MAX_NUM_CTS_DEF;
- param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
- param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
- param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
- param->wlan_elp_hp = PTA_ELP_HP_DEF;
- param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
- param->ack_mode_dual_ant = PTA_ACK_MODE_DEF;
- param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
- param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
- param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
+ param->per_threshold = cpu_to_le32(c->per_threshold);
+ param->max_scan_compensation_time =
+ cpu_to_le32(c->max_scan_compensation_time);
+ param->nfs_sample_interval = cpu_to_le16(c->nfs_sample_interval);
+ param->load_ratio = c->load_ratio;
+ param->auto_ps_mode = c->auto_ps_mode;
+ param->probe_req_compensation = c->probe_req_compensation;
+ param->scan_window_compensation = c->scan_window_compensation;
+ param->antenna_config = c->antenna_config;
+ param->beacon_miss_threshold = c->beacon_miss_threshold;
+ param->rate_adaptation_threshold =
+ cpu_to_le32(c->rate_adaptation_threshold);
+ param->rate_adaptation_snr = c->rate_adaptation_snr;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
if (ret < 0) {
@@ -534,8 +590,8 @@ int wl1271_acx_cca_threshold(struct wl1271 *wl)
goto out;
}
- detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
- detection->tx_energy_detection = 0;
+ detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold);
+ detection->tx_energy_detection = wl->conf.tx.tx_energy_detection;
ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD,
detection, sizeof(*detection));
@@ -562,10 +618,10 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
goto out;
}
- bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
- bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
- bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
- bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
+ bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout);
+ bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout);
+ bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps;
+ bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold;
ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
if (ret < 0) {
@@ -591,7 +647,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
goto out;
}
- acx_aid->aid = aid;
+ acx_aid->aid = cpu_to_le16(aid);
ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
if (ret < 0) {
@@ -618,9 +674,8 @@ int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask)
}
/* high event mask is unused */
- mask->high_event_mask = 0xffffffff;
-
- mask->event_mask = event_mask;
+ mask->high_event_mask = cpu_to_le32(0xffffffff);
+ mask->event_mask = cpu_to_le32(event_mask);
ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
mask, sizeof(*mask));
@@ -703,9 +758,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
return 0;
}
-int wl1271_acx_rate_policies(struct wl1271 *wl)
+int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
{
struct acx_rate_policy *acx;
+ struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx rate policies");
@@ -718,11 +774,11 @@ int wl1271_acx_rate_policies(struct wl1271 *wl)
}
/* configure one default (one-size-fits-all) rate class */
- acx->rate_class_cnt = 1;
- acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL;
- acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
- acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
- acx->rate_class[0].aflags = 0;
+ acx->rate_class_cnt = cpu_to_le32(1);
+ acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates);
+ acx->rate_class[0].short_retry_limit = c->short_retry_limit;
+ acx->rate_class[0].long_retry_limit = c->long_retry_limit;
+ acx->rate_class[0].aflags = c->aflags;
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
@@ -749,22 +805,14 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl)
goto out;
}
- /*
- * FIXME: Configure each AC with appropriate values (most suitable
- * values will probably be different for each AC.
- */
- for (i = 0; i < WL1271_ACX_AC_COUNT; i++) {
- acx->ac = i;
-
- /*
- * FIXME: The following default values originate from
- * the TI reference driver. What do they mean?
- */
- acx->cw_min = 15;
- acx->cw_max = 63;
- acx->aifsn = 3;
+ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
+ struct conf_tx_ac_category *c = &(wl->conf.tx.ac_conf[i]);
+ acx->ac = c->ac;
+ acx->cw_min = c->cw_min;
+ acx->cw_max = cpu_to_le16(c->cw_max);
+ acx->aifsn = c->aifsn;
acx->reserved = 0;
- acx->tx_op_limit = 0;
+ acx->tx_op_limit = cpu_to_le16(c->tx_op_limit);
ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
if (ret < 0) {
@@ -793,12 +841,15 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl)
goto out;
}
- /* FIXME: configure each TID with a different AC reference */
- for (i = 0; i < WL1271_ACX_TID_COUNT; i++) {
- acx->queue_id = i;
- acx->tsid = WL1271_ACX_AC_BE;
- acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY;
- acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY;
+ for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+ struct conf_tx_tid *c = &(wl->conf.tx.tid_conf[i]);
+ acx->queue_id = c->queue_id;
+ acx->channel_type = c->channel_type;
+ acx->tsid = c->tsid;
+ acx->ps_scheme = c->ps_scheme;
+ acx->ack_policy = c->ack_policy;
+ acx->apsd_conf[0] = cpu_to_le32(c->apsd_conf[0]);
+ acx->apsd_conf[1] = cpu_to_le32(c->apsd_conf[1]);
ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
if (ret < 0) {
@@ -826,7 +877,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl)
goto out;
}
- acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+ acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
@@ -852,8 +903,8 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl)
goto out;
}
- acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT;
- acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD;
+ acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout);
+ acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold);
ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of tx options failed: %d", ret);
@@ -879,11 +930,11 @@ int wl1271_acx_mem_cfg(struct wl1271 *wl)
}
/* memory config */
- mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+ mem_conf->num_stations = DEFAULT_NUM_STATIONS;
mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS;
mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS;
mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES;
- mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS;
+ mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
sizeof(*mem_conf));
@@ -906,7 +957,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
return ret;
wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!wl->target_mem_map) {
wl1271_error("couldn't allocate target memory map");
return -ENOMEM;
@@ -923,7 +974,8 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
}
/* initialize TX block book keeping */
- wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks;
+ wl->tx_blocks_available =
+ le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks);
wl1271_debug(DEBUG_TX, "available tx blocks: %d",
wl->tx_blocks_available);
@@ -943,10 +995,10 @@ int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
goto out;
}
- rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF;
- rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF;
- rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */
- rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY;
+ rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold);
+ rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout);
+ rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold);
+ rx_conf->queue_type = wl->conf.rx.queue_type;
ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf,
sizeof(*rx_conf));
@@ -959,3 +1011,124 @@ out:
kfree(rx_conf);
return ret;
}
+
+int wl1271_acx_smart_reflex(struct wl1271 *wl)
+{
+ struct acx_smart_reflex_state *sr_state = NULL;
+ struct acx_smart_reflex_config_params *sr_param = NULL;
+ int i, ret;
+
+ wl1271_debug(DEBUG_ACX, "acx smart reflex");
+
+ sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL);
+ if (!sr_param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) {
+ struct conf_mart_reflex_err_table *e =
+ &(wl->conf.init.sr_err_tbl[i]);
+
+ sr_param->error_table[i].len = e->len;
+ sr_param->error_table[i].upper_limit = e->upper_limit;
+ memcpy(sr_param->error_table[i].values, e->values, e->len);
+ }
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS,
+ sr_param, sizeof(*sr_param));
+ if (ret < 0) {
+ wl1271_warning("failed to set smart reflex params: %d", ret);
+ goto out;
+ }
+
+ sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
+ if (!sr_state) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* enable smart reflex */
+ sr_state->enable = wl->conf.init.sr_enable;
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE,
+ sr_state, sizeof(*sr_state));
+ if (ret < 0) {
+ wl1271_warning("failed to set smart reflex params: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(sr_state);
+ kfree(sr_param);
+ return ret;
+
+}
+
+int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
+{
+ struct wl1271_acx_bet_enable *acx = NULL;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx bet enable");
+
+ if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE)
+ goto out;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
+ acx->max_consecutive = wl->conf.conn.bet_max_consecutive;
+
+ ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx bet enable failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
+ u8 version)
+{
+ struct wl1271_acx_arp_filter *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->version = version;
+ acx->enable = enable;
+
+ if (enable == true) {
+ if (version == ACX_IPV4_VERSION)
+ memcpy(acx->address, address, ACX_IPV4_ADDR_SIZE);
+ else if (version == ACX_IPV6_VERSION)
+ memcpy(acx->address, address, sizeof(acx->address));
+ else
+ wl1271_error("Invalid IP version");
+ }
+
+ ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("failed to set arp ip filter: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 9068daaf0dd..2ce0a812854 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -61,8 +61,9 @@
WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA)
-#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \
- WL1271_ACX_INTR_EVENT_B | \
+#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \
+ WL1271_ACX_INTR_EVENT_B | \
+ WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA)
/* Target's information element */
@@ -70,11 +71,11 @@ struct acx_header {
struct wl1271_cmd_header cmd;
/* acx (or information element) header */
- u16 id;
+ __le16 id;
/* payload length (not including headers */
- u16 len;
-};
+ __le16 len;
+} __attribute__ ((packed));
struct acx_error_counter {
struct acx_header header;
@@ -82,21 +83,21 @@ struct acx_error_counter {
/* The number of PLCP errors since the last time this */
/* information element was interrogated. This field is */
/* automatically cleared when it is interrogated.*/
- u32 PLCP_error;
+ __le32 PLCP_error;
/* The number of FCS errors since the last time this */
/* information element was interrogated. This field is */
/* automatically cleared when it is interrogated.*/
- u32 FCS_error;
+ __le32 FCS_error;
/* The number of MPDUs without PLCP header errors received*/
/* since the last time this information element was interrogated. */
/* This field is automatically cleared when it is interrogated.*/
- u32 valid_frame;
+ __le32 valid_frame;
/* the number of missed sequence numbers in the squentially */
/* values of frames seq numbers */
- u32 seq_num_miss;
+ __le32 seq_num_miss;
} __attribute__ ((packed));
struct acx_revision {
@@ -125,7 +126,7 @@ struct acx_revision {
* (1 = first spin, 2 = second spin, and so on).
* bits 24 - 31: Chip ID - The WiLink chip ID.
*/
- u32 hw_version;
+ __le32 hw_version;
} __attribute__ ((packed));
enum wl1271_psm_mode {
@@ -170,7 +171,6 @@ enum {
#define DP_RX_PACKET_RING_CHUNK_NUM 2
#define DP_TX_PACKET_RING_CHUNK_NUM 2
#define DP_TX_COMPLETE_TIME_OUT 20
-#define FW_TX_CMPLT_BLOCK_SIZE 16
#define TX_MSDU_LIFETIME_MIN 0
#define TX_MSDU_LIFETIME_MAX 3000
@@ -186,7 +186,7 @@ struct acx_rx_msdu_lifetime {
* The maximum amount of time, in TU, before the
* firmware discards the MSDU.
*/
- u32 lifetime;
+ __le32 lifetime;
} __attribute__ ((packed));
/*
@@ -273,14 +273,14 @@ struct acx_rx_msdu_lifetime {
struct acx_rx_config {
struct acx_header header;
- u32 config_options;
- u32 filter_options;
+ __le32 config_options;
+ __le32 filter_options;
} __attribute__ ((packed));
struct acx_packet_detection {
struct acx_header header;
- u32 threshold;
+ __le32 threshold;
} __attribute__ ((packed));
@@ -302,8 +302,8 @@ struct acx_slot {
} __attribute__ ((packed));
-#define ADDRESS_GROUP_MAX (8)
-#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX)
+#define ACX_MC_ADDRESS_GROUP_MAX (8)
+#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX)
struct acx_dot11_grp_addr_tbl {
struct acx_header header;
@@ -314,40 +314,17 @@ struct acx_dot11_grp_addr_tbl {
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
} __attribute__ ((packed));
-
-#define RX_TIMEOUT_PS_POLL_MIN 0
-#define RX_TIMEOUT_PS_POLL_MAX (200000)
-#define RX_TIMEOUT_PS_POLL_DEF (15)
-#define RX_TIMEOUT_UPSD_MIN 0
-#define RX_TIMEOUT_UPSD_MAX (200000)
-#define RX_TIMEOUT_UPSD_DEF (15)
-
struct acx_rx_timeout {
struct acx_header header;
- /*
- * The longest time the STA will wait to receive
- * traffic from the AP after a PS-poll has been
- * transmitted.
- */
- u16 ps_poll_timeout;
-
- /*
- * The longest time the STA will wait to receive
- * traffic from the AP after a frame has been sent
- * from an UPSD enabled queue.
- */
- u16 upsd_timeout;
+ __le16 ps_poll_timeout;
+ __le16 upsd_timeout;
} __attribute__ ((packed));
-#define RTS_THRESHOLD_MIN 0
-#define RTS_THRESHOLD_MAX 4096
-#define RTS_THRESHOLD_DEF 2347
-
struct acx_rts_threshold {
struct acx_header header;
- u16 threshold;
+ __le16 threshold;
u8 pad[2];
} __attribute__ ((packed));
@@ -408,6 +385,13 @@ struct acx_beacon_filter_ie_table {
u8 pad[3];
} __attribute__ ((packed));
+struct acx_conn_monit_params {
+ struct acx_header header;
+
+ __le32 synch_fail_thold; /* number of beacons missed */
+ __le32 bss_lose_timeout; /* number of TU's from synch fail */
+} __attribute__ ((packed));
+
enum {
SG_ENABLE = 0,
SG_DISABLE,
@@ -431,6 +415,25 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __attribute__ ((packed));
+struct acx_smart_reflex_state {
+ struct acx_header header;
+
+ u8 enable;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+struct smart_reflex_err_table {
+ u8 len;
+ s8 upper_limit;
+ s8 values[14];
+} __attribute__ ((packed));
+
+struct acx_smart_reflex_config_params {
+ struct acx_header header;
+
+ struct smart_reflex_err_table error_table[3];
+} __attribute__ ((packed));
+
#define PTA_ANTENNA_TYPE_DEF (0)
#define PTA_BT_HP_MAXTIME_DEF (2000)
#define PTA_WLAN_HP_MAX_TIME_DEF (5000)
@@ -463,150 +466,34 @@ struct acx_bt_wlan_coex {
struct acx_bt_wlan_coex_param {
struct acx_header header;
- /*
- * The minimum rate of a received WLAN packet in the STA,
- * during protective mode, of which a new BT-HP request
- * during this Rx will always be respected and gain the antenna.
- */
- u32 min_rate;
-
- /* Max time the BT HP will be respected. */
- u16 bt_hp_max_time;
-
- /* Max time the WLAN HP will be respected. */
- u16 wlan_hp_max_time;
-
- /*
- * The time between the last BT activity
- * and the moment when the sense mode returns
- * to SENSE_INACTIVE.
- */
- u16 sense_disable_timer;
-
- /* Time before the next BT HP instance */
- u16 rx_time_bt_hp;
- u16 tx_time_bt_hp;
-
- /* range: 10-20000 default: 1500 */
- u16 rx_time_bt_hp_fast;
- u16 tx_time_bt_hp_fast;
-
- /* range: 2000-65535 default: 8700 */
- u16 wlan_cycle_fast;
-
- /* range: 0 - 15000 (Msec) default: 1000 */
- u16 bt_anti_starvation_period;
-
- /* range 400-10000(Usec) default: 3000 */
- u16 next_bt_lp_packet;
-
- /* Deafult: worst case for BT DH5 traffic */
- u16 wake_up_beacon;
-
- /* range: 0-50000(Usec) default: 1050 */
- u16 hp_dm_max_guard_time;
-
- /*
- * This is to prevent both BT & WLAN antenna
- * starvation.
- * Range: 100-50000(Usec) default:2550
- */
- u16 next_wlan_packet;
-
- /* 0 -> shared antenna */
- u8 antenna_type;
-
- /*
- * 0 -> TI legacy
- * 1 -> Palau
- */
- u8 signal_type;
-
- /*
- * BT AFH status
- * 0 -> no AFH
- * 1 -> from dedicated GPIO
- * 2 -> AFH on (from host)
- */
- u8 afh_leverage_on;
-
- /*
- * The number of cycles during which no
- * TX will be sent after 1 cycle of RX
- * transaction in protective mode
- */
- u8 quiet_cycle_num;
-
- /*
- * The maximum number of CTSs that will
- * be sent for receiving RX packet in
- * protective mode
- */
- u8 max_cts;
-
- /*
- * The number of WLAN packets
- * transferred in common mode before
- * switching to BT.
- */
- u8 wlan_packets_num;
-
- /*
- * The number of BT packets
- * transferred in common mode before
- * switching to WLAN.
- */
- u8 bt_packets_num;
-
- /* range: 1-255 default: 5 */
- u8 missed_rx_avalanche;
-
- /* range: 0-1 default: 1 */
- u8 wlan_elp_hp;
-
- /* range: 0 - 15 default: 4 */
- u8 bt_anti_starvation_cycles;
-
- u8 ack_mode_dual_ant;
-
- /*
- * Allow PA_SD assertion/de-assertion
- * during enabled BT activity.
- */
- u8 pa_sd_enable;
-
- /*
- * Enable/Disable PTA in auto mode:
- * Support Both Active & P.S modes
- */
- u8 pta_auto_mode_enable;
-
- /* range: 0 - 20 default: 1 */
- u8 bt_hp_respected_num;
+ __le32 per_threshold;
+ __le32 max_scan_compensation_time;
+ __le16 nfs_sample_interval;
+ u8 load_ratio;
+ u8 auto_ps_mode;
+ u8 probe_req_compensation;
+ u8 scan_window_compensation;
+ u8 antenna_config;
+ u8 beacon_miss_threshold;
+ __le32 rate_adaptation_threshold;
+ s8 rate_adaptation_snr;
+ u8 padding[3];
} __attribute__ ((packed));
-#define CCA_THRSH_ENABLE_ENERGY_D 0x140A
-#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF
-
struct acx_energy_detection {
struct acx_header header;
/* The RX Clear Channel Assessment threshold in the PHY */
- u16 rx_cca_threshold;
+ __le16 rx_cca_threshold;
u8 tx_energy_detection;
u8 pad;
} __attribute__ ((packed));
-#define BCN_RX_TIMEOUT_DEF_VALUE 10000
-#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000
-#define RX_BROADCAST_IN_PS_DEF_VALUE 1
-#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4
-
struct acx_beacon_broadcast {
struct acx_header header;
- u16 beacon_rx_timeout;
- u16 broadcast_timeout;
+ __le16 beacon_rx_timeout;
+ __le16 broadcast_timeout;
/* Enables receiving of broadcast packets in PS mode */
u8 rx_broadcast_in_ps;
@@ -619,8 +506,8 @@ struct acx_beacon_broadcast {
struct acx_event_mask {
struct acx_header header;
- u32 event_mask;
- u32 high_event_mask; /* Unused */
+ __le32 event_mask;
+ __le32 high_event_mask; /* Unused */
} __attribute__ ((packed));
#define CFG_RX_FCS BIT(2)
@@ -657,11 +544,15 @@ struct acx_event_mask {
#define SCAN_TRIGGERED BIT(2)
#define SCAN_PRIORITY_HIGH BIT(3)
+/* When set, disable HW encryption */
+#define DF_ENCRYPTION_DISABLE 0x01
+#define DF_SNIFF_MODE_ENABLE 0x80
+
struct acx_feature_config {
struct acx_header header;
- u32 options;
- u32 data_flow_options;
+ __le32 options;
+ __le32 data_flow_options;
} __attribute__ ((packed));
struct acx_current_tx_power {
@@ -671,14 +562,6 @@ struct acx_current_tx_power {
u8 padding[3];
} __attribute__ ((packed));
-enum acx_wake_up_event {
- WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
- WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/
- WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */
- WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */
- WAKE_UP_EVENT_BITS_MASK = 0x0F
-};
-
struct acx_wake_up_condition {
struct acx_header header;
@@ -693,7 +576,7 @@ struct acx_aid {
/*
* To be set when associated with an AP.
*/
- u16 aid;
+ __le16 aid;
u8 pad[2];
} __attribute__ ((packed));
@@ -725,152 +608,152 @@ struct acx_ctsprotect {
} __attribute__ ((packed));
struct acx_tx_statistics {
- u32 internal_desc_overflow;
+ __le32 internal_desc_overflow;
} __attribute__ ((packed));
struct acx_rx_statistics {
- u32 out_of_mem;
- u32 hdr_overflow;
- u32 hw_stuck;
- u32 dropped;
- u32 fcs_err;
- u32 xfr_hint_trig;
- u32 path_reset;
- u32 reset_counter;
+ __le32 out_of_mem;
+ __le32 hdr_overflow;
+ __le32 hw_stuck;
+ __le32 dropped;
+ __le32 fcs_err;
+ __le32 xfr_hint_trig;
+ __le32 path_reset;
+ __le32 reset_counter;
} __attribute__ ((packed));
struct acx_dma_statistics {
- u32 rx_requested;
- u32 rx_errors;
- u32 tx_requested;
- u32 tx_errors;
+ __le32 rx_requested;
+ __le32 rx_errors;
+ __le32 tx_requested;
+ __le32 tx_errors;
} __attribute__ ((packed));
struct acx_isr_statistics {
/* host command complete */
- u32 cmd_cmplt;
+ __le32 cmd_cmplt;
/* fiqisr() */
- u32 fiqs;
+ __le32 fiqs;
/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
- u32 rx_headers;
+ __le32 rx_headers;
/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
- u32 rx_completes;
+ __le32 rx_completes;
/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
- u32 rx_mem_overflow;
+ __le32 rx_mem_overflow;
/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
- u32 rx_rdys;
+ __le32 rx_rdys;
/* irqisr() */
- u32 irqs;
+ __le32 irqs;
/* (INT_STS_ND & INT_TRIG_TX_PROC) */
- u32 tx_procs;
+ __le32 tx_procs;
/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
- u32 decrypt_done;
+ __le32 decrypt_done;
/* (INT_STS_ND & INT_TRIG_DMA0) */
- u32 dma0_done;
+ __le32 dma0_done;
/* (INT_STS_ND & INT_TRIG_DMA1) */
- u32 dma1_done;
+ __le32 dma1_done;
/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
- u32 tx_exch_complete;
+ __le32 tx_exch_complete;
/* (INT_STS_ND & INT_TRIG_COMMAND) */
- u32 commands;
+ __le32 commands;
/* (INT_STS_ND & INT_TRIG_RX_PROC) */
- u32 rx_procs;
+ __le32 rx_procs;
/* (INT_STS_ND & INT_TRIG_PM_802) */
- u32 hw_pm_mode_changes;
+ __le32 hw_pm_mode_changes;
/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
- u32 host_acknowledges;
+ __le32 host_acknowledges;
/* (INT_STS_ND & INT_TRIG_PM_PCI) */
- u32 pci_pm;
+ __le32 pci_pm;
/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
- u32 wakeups;
+ __le32 wakeups;
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
- u32 low_rssi;
+ __le32 low_rssi;
} __attribute__ ((packed));
struct acx_wep_statistics {
/* WEP address keys configured */
- u32 addr_key_count;
+ __le32 addr_key_count;
/* default keys configured */
- u32 default_key_count;
+ __le32 default_key_count;
- u32 reserved;
+ __le32 reserved;
/* number of times that WEP key not found on lookup */
- u32 key_not_found;
+ __le32 key_not_found;
/* number of times that WEP key decryption failed */
- u32 decrypt_fail;
+ __le32 decrypt_fail;
/* WEP packets decrypted */
- u32 packets;
+ __le32 packets;
/* WEP decrypt interrupts */
- u32 interrupt;
+ __le32 interrupt;
} __attribute__ ((packed));
#define ACX_MISSED_BEACONS_SPREAD 10
struct acx_pwr_statistics {
/* the amount of enters into power save mode (both PD & ELP) */
- u32 ps_enter;
+ __le32 ps_enter;
/* the amount of enters into ELP mode */
- u32 elp_enter;
+ __le32 elp_enter;
/* the amount of missing beacon interrupts to the host */
- u32 missing_bcns;
+ __le32 missing_bcns;
/* the amount of wake on host-access times */
- u32 wake_on_host;
+ __le32 wake_on_host;
/* the amount of wake on timer-expire */
- u32 wake_on_timer_exp;
+ __le32 wake_on_timer_exp;
/* the number of packets that were transmitted with PS bit set */
- u32 tx_with_ps;
+ __le32 tx_with_ps;
/* the number of packets that were transmitted with PS bit clear */
- u32 tx_without_ps;
+ __le32 tx_without_ps;
/* the number of received beacons */
- u32 rcvd_beacons;
+ __le32 rcvd_beacons;
/* the number of entering into PowerOn (power save off) */
- u32 power_save_off;
+ __le32 power_save_off;
/* the number of entries into power save mode */
- u16 enable_ps;
+ __le16 enable_ps;
/*
* the number of exits from power save, not including failed PS
* transitions
*/
- u16 disable_ps;
+ __le16 disable_ps;
/*
* the number of times the TSF counter was adjusted because
* of drift
*/
- u32 fix_tsf_ps;
+ __le32 fix_tsf_ps;
/* Gives statistics about the spread continuous missed beacons.
* The 16 LSB are dedicated for the PS mode.
@@ -881,53 +764,53 @@ struct acx_pwr_statistics {
* ...
* cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
*/
- u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
+ __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
/* the number of beacons in awake mode */
- u32 rcvd_awake_beacons;
+ __le32 rcvd_awake_beacons;
} __attribute__ ((packed));
struct acx_mic_statistics {
- u32 rx_pkts;
- u32 calc_failure;
+ __le32 rx_pkts;
+ __le32 calc_failure;
} __attribute__ ((packed));
struct acx_aes_statistics {
- u32 encrypt_fail;
- u32 decrypt_fail;
- u32 encrypt_packets;
- u32 decrypt_packets;
- u32 encrypt_interrupt;
- u32 decrypt_interrupt;
+ __le32 encrypt_fail;
+ __le32 decrypt_fail;
+ __le32 encrypt_packets;
+ __le32 decrypt_packets;
+ __le32 encrypt_interrupt;
+ __le32 decrypt_interrupt;
} __attribute__ ((packed));
struct acx_event_statistics {
- u32 heart_beat;
- u32 calibration;
- u32 rx_mismatch;
- u32 rx_mem_empty;
- u32 rx_pool;
- u32 oom_late;
- u32 phy_transmit_error;
- u32 tx_stuck;
+ __le32 heart_beat;
+ __le32 calibration;
+ __le32 rx_mismatch;
+ __le32 rx_mem_empty;
+ __le32 rx_pool;
+ __le32 oom_late;
+ __le32 phy_transmit_error;
+ __le32 tx_stuck;
} __attribute__ ((packed));
struct acx_ps_statistics {
- u32 pspoll_timeouts;
- u32 upsd_timeouts;
- u32 upsd_max_sptime;
- u32 upsd_max_apturn;
- u32 pspoll_max_apturn;
- u32 pspoll_utilization;
- u32 upsd_utilization;
+ __le32 pspoll_timeouts;
+ __le32 upsd_timeouts;
+ __le32 upsd_max_sptime;
+ __le32 upsd_max_apturn;
+ __le32 pspoll_max_apturn;
+ __le32 pspoll_utilization;
+ __le32 upsd_utilization;
} __attribute__ ((packed));
struct acx_rxpipe_statistics {
- u32 rx_prep_beacon_drop;
- u32 descr_host_int_trig_rx_data;
- u32 beacon_buffer_thres_host_int_trig_rx_data;
- u32 missed_beacon_host_int_trig_rx_data;
- u32 tx_xfr_host_int_trig_rx_data;
+ __le32 rx_prep_beacon_drop;
+ __le32 descr_host_int_trig_rx_data;
+ __le32 beacon_buffer_thres_host_int_trig_rx_data;
+ __le32 missed_beacon_host_int_trig_rx_data;
+ __le32 tx_xfr_host_int_trig_rx_data;
} __attribute__ ((packed));
struct acx_statistics {
@@ -946,13 +829,8 @@ struct acx_statistics {
struct acx_rxpipe_statistics rxpipe;
} __attribute__ ((packed));
-#define ACX_MAX_RATE_CLASSES 8
-#define ACX_RATE_MASK_UNSPECIFIED 0
-#define ACX_RATE_MASK_ALL 0x1eff
-#define ACX_RATE_RETRY_LIMIT 10
-
struct acx_rate_class {
- u32 enabled_rates;
+ __le32 enabled_rates;
u8 short_retry_limit;
u8 long_retry_limit;
u8 aflags;
@@ -962,47 +840,20 @@ struct acx_rate_class {
struct acx_rate_policy {
struct acx_header header;
- u32 rate_class_cnt;
- struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
+ __le32 rate_class_cnt;
+ struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
} __attribute__ ((packed));
-#define WL1271_ACX_AC_COUNT 4
-
struct acx_ac_cfg {
struct acx_header header;
u8 ac;
u8 cw_min;
- u16 cw_max;
+ __le16 cw_max;
u8 aifsn;
u8 reserved;
- u16 tx_op_limit;
+ __le16 tx_op_limit;
} __attribute__ ((packed));
-enum wl1271_acx_ac {
- WL1271_ACX_AC_BE = 0,
- WL1271_ACX_AC_BK = 1,
- WL1271_ACX_AC_VI = 2,
- WL1271_ACX_AC_VO = 3,
- WL1271_ACX_AC_CTS2SELF = 4,
- WL1271_ACX_AC_ANY_TID = 0x1F,
- WL1271_ACX_AC_INVALID = 0xFF,
-};
-
-enum wl1271_acx_ps_scheme {
- WL1271_ACX_PS_SCHEME_LEGACY = 0,
- WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1,
- WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2,
- WL1271_ACX_PS_SCHEME_SAPSD = 3,
-};
-
-enum wl1271_acx_ack_policy {
- WL1271_ACX_ACK_POLICY_LEGACY = 0,
- WL1271_ACX_ACK_POLICY_NO_ACK = 1,
- WL1271_ACX_ACK_POLICY_BLOCK = 2,
-};
-
-#define WL1271_ACX_TID_COUNT 7
-
struct acx_tid_config {
struct acx_header header;
u8 queue_id;
@@ -1011,22 +862,19 @@ struct acx_tid_config {
u8 ps_scheme;
u8 ack_policy;
u8 padding[3];
- u32 apsd_conf[2];
+ __le32 apsd_conf[2];
} __attribute__ ((packed));
struct acx_frag_threshold {
struct acx_header header;
- u16 frag_threshold;
+ __le16 frag_threshold;
u8 padding[2];
} __attribute__ ((packed));
-#define WL1271_ACX_TX_COMPL_TIMEOUT 5
-#define WL1271_ACX_TX_COMPL_THRESHOLD 5
-
struct acx_tx_config_options {
struct acx_header header;
- u16 tx_compl_timeout; /* msec */
- u16 tx_compl_threshold; /* number of packets */
+ __le16 tx_compl_timeout; /* msec */
+ __le16 tx_compl_threshold; /* number of packets */
} __attribute__ ((packed));
#define ACX_RX_MEM_BLOCKS 64
@@ -1041,79 +889,87 @@ struct wl1271_acx_config_memory {
u8 tx_min_mem_block_num;
u8 num_stations;
u8 num_ssid_profiles;
- u32 total_tx_descriptors;
+ __le32 total_tx_descriptors;
} __attribute__ ((packed));
struct wl1271_acx_mem_map {
struct acx_header header;
- void *code_start;
- void *code_end;
+ __le32 code_start;
+ __le32 code_end;
- void *wep_defkey_start;
- void *wep_defkey_end;
+ __le32 wep_defkey_start;
+ __le32 wep_defkey_end;
- void *sta_table_start;
- void *sta_table_end;
+ __le32 sta_table_start;
+ __le32 sta_table_end;
- void *packet_template_start;
- void *packet_template_end;
+ __le32 packet_template_start;
+ __le32 packet_template_end;
/* Address of the TX result interface (control block) */
- u32 tx_result;
- u32 tx_result_queue_start;
+ __le32 tx_result;
+ __le32 tx_result_queue_start;
- void *queue_memory_start;
- void *queue_memory_end;
+ __le32 queue_memory_start;
+ __le32 queue_memory_end;
- u32 packet_memory_pool_start;
- u32 packet_memory_pool_end;
+ __le32 packet_memory_pool_start;
+ __le32 packet_memory_pool_end;
- void *debug_buffer1_start;
- void *debug_buffer1_end;
+ __le32 debug_buffer1_start;
+ __le32 debug_buffer1_end;
- void *debug_buffer2_start;
- void *debug_buffer2_end;
+ __le32 debug_buffer2_start;
+ __le32 debug_buffer2_end;
/* Number of blocks FW allocated for TX packets */
- u32 num_tx_mem_blocks;
+ __le32 num_tx_mem_blocks;
/* Number of blocks FW allocated for RX packets */
- u32 num_rx_mem_blocks;
+ __le32 num_rx_mem_blocks;
/* the following 4 fields are valid in SLAVE mode only */
u8 *tx_cbuf;
u8 *rx_cbuf;
- void *rx_ctrl;
- void *tx_ctrl;
+ __le32 rx_ctrl;
+ __le32 tx_ctrl;
} __attribute__ ((packed));
-enum wl1271_acx_rx_queue_type {
- RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */
- RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */
- RX_QUEUE_TYPE_NUM,
- RX_QUEUE_TYPE_MAX = USHORT_MAX
-};
-
-#define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on
- * every event */
-#define WL1271_RX_INTR_THRESHOLD_MIN 0
-#define WL1271_RX_INTR_THRESHOLD_MAX 15
-
-#define WL1271_RX_INTR_TIMEOUT_DEF 5
-#define WL1271_RX_INTR_TIMEOUT_MIN 1
-#define WL1271_RX_INTR_TIMEOUT_MAX 100
-
struct wl1271_acx_rx_config_opt {
struct acx_header header;
- u16 mblk_threshold;
- u16 threshold;
- u16 timeout;
+ __le16 mblk_threshold;
+ __le16 threshold;
+ __le16 timeout;
u8 queue_type;
u8 reserved;
} __attribute__ ((packed));
+
+struct wl1271_acx_bet_enable {
+ struct acx_header header;
+
+ u8 enable;
+ u8 max_consecutive;
+ u8 padding[2];
+} __attribute__ ((packed));
+
+#define ACX_IPV4_VERSION 4
+#define ACX_IPV6_VERSION 6
+#define ACX_IPV4_ADDR_SIZE 4
+struct wl1271_acx_arp_filter {
+ struct acx_header header;
+ u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
+ u8 enable; /* 1 to enable ARP filtering, 0 to disable */
+ u8 padding[2];
+ u8 address[16]; /* The configured device IP address - all ARP
+ requests directed to this IP address will pass
+ through. For IPv4, the first four bytes are
+ used. */
+} __attribute__((packed));
+
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1170,6 +1026,9 @@ enum {
ACX_PEER_HT_CAP = 0x0057,
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
+ ACX_SET_SMART_REFLEX_DEBUG = 0x005A,
+ ACX_SET_SMART_REFLEX_STATE = 0x005B,
+ ACX_SET_SMART_REFLEX_PARAMS = 0x005F,
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D,
DOT11_RX_DOT11_MODE = 0x1012,
@@ -1182,23 +1041,24 @@ enum {
};
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
- u8 listen_interval);
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl);
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len);
int wl1271_acx_tx_power(struct wl1271 *wl, int power);
int wl1271_acx_feature_cfg(struct wl1271 *wl);
int wl1271_acx_mem_map(struct wl1271 *wl,
struct acx_header *mem_map, size_t len);
-int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time);
+int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl);
int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter);
int wl1271_acx_pd_threshold(struct wl1271 *wl);
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
-int wl1271_acx_group_address_tbl(struct wl1271 *wl);
+int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
+ void *mc_list, u32 mc_list_len);
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
-int wl1271_acx_beacon_filter_opt(struct wl1271 *wl);
+int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
+int wl1271_acx_conn_monit_params(struct wl1271 *wl);
int wl1271_acx_sg_enable(struct wl1271 *wl);
int wl1271_acx_sg_cfg(struct wl1271 *wl);
int wl1271_acx_cca_threshold(struct wl1271 *wl);
@@ -1207,9 +1067,9 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask);
int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int wl1271_acx_cts_protect(struct wl1271 *wl,
- enum acx_ctsprotect_type ctsprotect);
+ enum acx_ctsprotect_type ctsprotect);
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
-int wl1271_acx_rate_policies(struct wl1271 *wl);
+int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates);
int wl1271_acx_ac_cfg(struct wl1271 *wl);
int wl1271_acx_tid_cfg(struct wl1271 *wl);
int wl1271_acx_frag_threshold(struct wl1271 *wl);
@@ -1217,5 +1077,9 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
+int wl1271_acx_smart_reflex(struct wl1271 *wl);
+int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
+ u8 version);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index 8228ef474a7..ba4a2b4f0f5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -39,6 +39,14 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
.start = REGISTERS_BASE,
.size = 0x00008800
},
+ .mem2 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ .mem3 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
},
[PART_WORK] = {
@@ -48,7 +56,15 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
},
.reg = {
.start = REGISTERS_BASE,
- .size = 0x0000b000
+ .size = 0x0000a000
+ },
+ .mem2 = {
+ .start = 0x003004f8,
+ .size = 0x00000004
+ },
+ .mem3 = {
+ .start = 0x00040404,
+ .size = 0x00000000
},
},
@@ -60,6 +76,14 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
.reg = {
.start = DRPW_BASE,
.size = 0x00006000
+ },
+ .mem2 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ .mem3 = {
+ .start = 0x00000000,
+ .size = 0x00000000
}
}
};
@@ -69,19 +93,19 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */
- cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */
cpu_ctrl |= flag;
- wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+ wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
static void wl1271_boot_fw_version(struct wl1271 *wl)
{
struct wl1271_static_data static_data;
- wl1271_spi_mem_read(wl, wl->cmd_box_addr,
- &static_data, sizeof(static_data));
+ wl1271_spi_read(wl, wl->cmd_box_addr,
+ &static_data, sizeof(static_data), false);
strncpy(wl->chip.fw_ver, static_data.fw_version,
sizeof(wl->chip.fw_ver));
@@ -93,8 +117,9 @@ static void wl1271_boot_fw_version(struct wl1271 *wl)
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
size_t fw_data_len, u32 dest)
{
+ struct wl1271_partition_set partition;
int addr, chunk_num, partition_limit;
- u8 *p;
+ u8 *p, *chunk;
/* whal_FwCtrl_LoadFwImageSm() */
@@ -103,16 +128,20 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
fw_data_len, CHUNK_SIZE);
-
if ((fw_data_len % 4) != 0) {
wl1271_error("firmware length not multiple of four");
return -EIO;
}
- wl1271_set_partition(wl, dest,
- part_table[PART_DOWN].mem.size,
- part_table[PART_DOWN].reg.start,
- part_table[PART_DOWN].reg.size);
+ chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+ if (!chunk) {
+ wl1271_error("allocation for firmware upload chunk failed");
+ return -ENOMEM;
+ }
+
+ memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
+ partition.mem.start = dest;
+ wl1271_set_partition(wl, &partition);
/* 10.1 set partition limit and chunk num */
chunk_num = 0;
@@ -125,21 +154,17 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
addr = dest + chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE +
part_table[PART_DOWN].mem.size;
-
- /* FIXME: Over 80 chars! */
- wl1271_set_partition(wl,
- addr,
- part_table[PART_DOWN].mem.size,
- part_table[PART_DOWN].reg.start,
- part_table[PART_DOWN].reg.size);
+ partition.mem.start = addr;
+ wl1271_set_partition(wl, &partition);
}
/* 10.3 upload the chunk */
addr = dest + chunk_num * CHUNK_SIZE;
p = buf + chunk_num * CHUNK_SIZE;
+ memcpy(chunk, p, CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
- wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+ wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false);
chunk_num++;
}
@@ -147,28 +172,31 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
/* 10.4 upload the last chunk */
addr = dest + chunk_num * CHUNK_SIZE;
p = buf + chunk_num * CHUNK_SIZE;
+ memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
- wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+ wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
+ kfree(chunk);
return 0;
}
static int wl1271_boot_upload_firmware(struct wl1271 *wl)
{
u32 chunks, addr, len;
+ int ret = 0;
u8 *fw;
fw = wl->fw;
- chunks = be32_to_cpup((u32 *) fw);
+ chunks = be32_to_cpup((__be32 *) fw);
fw += sizeof(u32);
wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
while (chunks--) {
- addr = be32_to_cpup((u32 *) fw);
+ addr = be32_to_cpup((__be32 *) fw);
fw += sizeof(u32);
- len = be32_to_cpup((u32 *) fw);
+ len = be32_to_cpup((__be32 *) fw);
fw += sizeof(u32);
if (len > 300000) {
@@ -177,11 +205,13 @@ static int wl1271_boot_upload_firmware(struct wl1271 *wl)
}
wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
chunks, addr, len);
- wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
+ ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
+ if (ret != 0)
+ break;
fw += len;
}
- return 0;
+ return ret;
}
static int wl1271_boot_upload_nvs(struct wl1271 *wl)
@@ -235,7 +265,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
- wl1271_reg_write32(wl, dest_addr, val);
+ wl1271_spi_write32(wl, dest_addr, val);
nvs_ptr += 4;
dest_addr += 4;
@@ -253,20 +283,18 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/* FIXME: The driver sets the partition here, but this is not needed,
since it sets to the same one as currently in use */
/* Now we must set the partition correctly */
- wl1271_set_partition(wl,
- part_table[PART_WORK].mem.start,
- part_table[PART_WORK].mem.size,
- part_table[PART_WORK].reg.start,
- part_table[PART_WORK].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
+ if (!nvs_aligned)
+ return -ENOMEM;
/* And finally we upload the NVS tables */
/* FIXME: In wl1271, we upload everything at once.
No endianness handling needed here?! The ref driver doesn't do
anything about it at this point */
- wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len);
+ wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
kfree(nvs_aligned);
return 0;
@@ -275,9 +303,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
{
enable_irq(wl->irq);
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
- wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+ wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
static int wl1271_boot_soft_reset(struct wl1271 *wl)
@@ -286,12 +314,13 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
u32 boot_data;
/* perform soft reset */
- wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+ wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET,
+ ACX_SLV_SOFT_RESET_BIT);
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) {
- boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET);
wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
@@ -307,10 +336,10 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
}
/* disable Rx/Tx */
- wl1271_reg_write32(wl, ENABLE, 0x0);
+ wl1271_spi_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
- wl1271_reg_write32(wl, SPARE_A2, 0xffff);
+ wl1271_spi_write32(wl, SPARE_A2, 0xffff);
return 0;
}
@@ -322,7 +351,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
- chip_id = wl1271_reg_read32(wl, CHIP_ID_B);
+ chip_id = wl1271_spi_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
@@ -335,7 +364,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
- interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ interrupt = wl1271_spi_read32(wl,
+ ACX_REG_INTERRUPT_NO_CLEAR);
if (interrupt == 0xffffffff) {
wl1271_error("error reading hardware complete "
@@ -344,7 +374,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
break;
}
@@ -357,17 +387,13 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* get hardware config command mail box */
- wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+ wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */
- wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
- wl1271_set_partition(wl,
- part_table[PART_WORK].mem.start,
- part_table[PART_WORK].mem.size,
- part_table[PART_WORK].reg.start,
- part_table[PART_WORK].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_WORK]);
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
wl->cmd_box_addr, wl->event_box_addr);
@@ -379,11 +405,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
* ready to receive event from the command mailbox
*/
- /* enable gpio interrupts */
- wl1271_boot_enable_interrupts(wl);
-
- /* unmask all mbox events */
- wl->event_mask = 0xffffffff;
+ /* unmask required mbox events */
+ wl->event_mask = BSS_LOSE_EVENT_ID |
+ SCAN_COMPLETE_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {
@@ -399,34 +423,13 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
{
- u32 polarity, status, i;
-
- wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
- wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ);
-
- /* Wait until the command is complete (ie. bit 18 is set) */
- for (i = 0; i < OCP_CMD_LOOP; i++) {
- polarity = wl1271_reg_read32(wl, OCP_DATA_READ);
- if (polarity & OCP_READY_MASK)
- break;
- }
- if (i == OCP_CMD_LOOP) {
- wl1271_error("OCP command timeout!");
- return -EIO;
- }
+ u32 polarity;
- status = polarity & OCP_STATUS_MASK;
- if (status != OCP_STATUS_OK) {
- wl1271_error("OCP command failed (%d)", status);
- return -EIO;
- }
+ polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
/* We use HIGH polarity, so unset the LOW bit */
polarity &= ~POLARITY_LOW;
-
- wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
- wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity);
- wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE);
+ wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
return 0;
}
@@ -436,16 +439,32 @@ int wl1271_boot(struct wl1271 *wl)
int ret = 0;
u32 tmp, clk, pause;
- if (REF_CLOCK == 0 || REF_CLOCK == 2)
- /* ref clk: 19.2/38.4 */
+ if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
+ /* ref clk: 19.2/38.4/38.4-XTAL */
clk = 0x3;
else if (REF_CLOCK == 1 || REF_CLOCK == 3)
/* ref clk: 26/52 */
clk = 0x5;
- wl1271_reg_write32(wl, PLL_PARAMETERS, clk);
+ if (REF_CLOCK != 0) {
+ u16 val;
+ /* Set clock type */
+ val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
+ val &= FREF_CLK_TYPE_BITS;
+ val |= CLK_REQ_PRCM;
+ wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
+ } else {
+ u16 val;
+ /* Set clock polarity */
+ val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
+ val &= FREF_CLK_POLARITY_BITS;
+ val |= CLK_REQ_OUTN_SEL;
+ wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
+ }
+
+ wl1271_spi_write32(wl, PLL_PARAMETERS, clk);
- pause = wl1271_reg_read32(wl, PLL_PARAMETERS);
+ pause = wl1271_spi_read32(wl, PLL_PARAMETERS);
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
@@ -454,39 +473,31 @@ int wl1271_boot(struct wl1271 *wl)
* 0x3ff (magic number ). How does
* this work?! */
pause |= WU_COUNTER_PAUSE_VAL;
- wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause);
+ wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause);
/* Continue the ELP wake up sequence */
- wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+ wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
- wl1271_set_partition(wl,
- part_table[PART_DRPW].mem.start,
- part_table[PART_DRPW].mem.size,
- part_table[PART_DRPW].reg.start,
- part_table[PART_DRPW].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_DRPW]);
/* Read-modify-write DRPW_SCRATCH_START register (see next state)
to be used by DRPw FW. The RTRIM value will be added by the FW
before taking DRPw out of reset */
wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
- clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START);
+ clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START);
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
/* 2 */
clk |= (REF_CLOCK << 1) << 4;
- wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk);
+ wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk);
- wl1271_set_partition(wl,
- part_table[PART_WORK].mem.start,
- part_table[PART_WORK].mem.size,
- part_table[PART_WORK].reg.start,
- part_table[PART_WORK].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Disable interrupts */
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
ret = wl1271_boot_soft_reset(wl);
if (ret < 0)
@@ -501,21 +512,22 @@ int wl1271_boot(struct wl1271 *wl)
* ACX_EEPROMLESS_IND_REG */
wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
- wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
+ wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG,
+ ACX_EEPROMLESS_IND_REG);
- tmp = wl1271_reg_read32(wl, CHIP_ID_B);
+ tmp = wl1271_spi_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
/* 6. read the EEPROM parameters */
- tmp = wl1271_reg_read32(wl, SCR_PAD2);
+ tmp = wl1271_spi_read32(wl, SCR_PAD2);
ret = wl1271_boot_write_irq_polarity(wl);
if (ret < 0)
goto out;
/* FIXME: Need to check whether this is really what we want */
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR);
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
@@ -530,6 +542,9 @@ int wl1271_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
+ /* Enable firmware interrupts now */
+ wl1271_boot_enable_interrupts(wl);
+
/* set the wl1271 default filters */
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h
index b0d8fb46a43..412443ee655 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.h
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.h
@@ -50,23 +50,17 @@ struct wl1271_static_data {
#define WU_COUNTER_PAUSE_VAL 0x3FF
#define WELP_ARM_COMMAND_VAL 0x4
-#define OCP_CMD_LOOP 32
-
-#define OCP_CMD_WRITE 0x1
-#define OCP_CMD_READ 0x2
-
-#define OCP_READY_MASK BIT(18)
-#define OCP_STATUS_MASK (BIT(16) | BIT(17))
-
-#define OCP_STATUS_NO_RESP 0x00000
-#define OCP_STATUS_OK 0x10000
-#define OCP_STATUS_REQ_FAILED 0x20000
-#define OCP_STATUS_RESP_ERROR 0x30000
-
-#define OCP_REG_POLARITY 0x30032
+#define OCP_REG_POLARITY 0x0064
+#define OCP_REG_CLK_TYPE 0x0448
+#define OCP_REG_CLK_POLARITY 0x0cb2
#define CMD_MBOX_ADDRESS 0x407B4
#define POLARITY_LOW BIT(1)
+#define FREF_CLK_TYPE_BITS 0xfffffe7f
+#define CLK_REQ_PRCM 0x100
+#define FREF_CLK_POLARITY_BITS 0xfffff8ff
+#define CLK_REQ_OUTN_SEL 0x700
+
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 2a4351ff54d..0666328ce9a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -50,18 +50,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
int ret = 0;
cmd = buf;
- cmd->id = id;
+ cmd->id = cpu_to_le16(id);
cmd->status = 0;
WARN_ON(len % 4 != 0);
- wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+ wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false);
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
@@ -71,17 +71,17 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
msleep(1);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
}
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
out:
return ret;
}
-int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
+static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
{
struct wl1271_cmd_cal_channel_tune *cmd;
int ret = 0;
@@ -104,7 +104,7 @@ int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
+static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
{
struct wl1271_cmd_cal_update_ref_point *cmd;
int ret = 0;
@@ -129,7 +129,7 @@ int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_cal_p2g(struct wl1271 *wl)
+static int wl1271_cmd_cal_p2g(struct wl1271 *wl)
{
struct wl1271_cmd_cal_p2g *cmd;
int ret = 0;
@@ -150,7 +150,7 @@ int wl1271_cmd_cal_p2g(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_cal(struct wl1271 *wl)
+static int wl1271_cmd_cal(struct wl1271 *wl)
{
/*
* FIXME: we must make sure that we're not sleeping when calibration
@@ -175,11 +175,9 @@ int wl1271_cmd_cal(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait)
+int wl1271_cmd_join(struct wl1271 *wl)
{
static bool do_cal = true;
- unsigned long timeout;
struct wl1271_cmd_join *join;
int ret, i;
u8 *bssid;
@@ -193,6 +191,18 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
do_cal = false;
}
+ /* FIXME: This is a workaround, because with the current stack, we
+ * cannot know when we have disassociated. So, if we have already
+ * joined, we disconnect before joining again. */
+ if (wl->joined) {
+ ret = wl1271_cmd_disconnect(wl);
+ if (ret < 0) {
+ wl1271_error("failed to disconnect before rejoining");
+ goto out;
+ }
+
+ wl->joined = false;
+ }
join = kzalloc(sizeof(*join), GFP_KERNEL);
if (!join) {
@@ -207,15 +217,34 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
for (i = 0; i < ETH_ALEN; i++)
bssid[i] = wl->bssid[ETH_ALEN - i - 1];
- join->rx_config_options = wl->rx_config;
- join->rx_filter_options = wl->rx_filter;
+ join->rx_config_options = cpu_to_le32(wl->rx_config);
+ join->rx_filter_options = cpu_to_le32(wl->rx_filter);
+ join->bss_type = wl->bss_type;
- join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
- RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+ /*
+ * FIXME: disable temporarily all filters because after commit
+ * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
+ * association. The filter logic needs to be implemented properly
+ * and once that is done, this hack can be removed.
+ */
+ join->rx_config_options = cpu_to_le32(0);
+ join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER);
+
+ if (wl->band == IEEE80211_BAND_2GHZ)
+ join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS |
+ CONF_HW_BIT_RATE_2MBPS |
+ CONF_HW_BIT_RATE_5_5MBPS |
+ CONF_HW_BIT_RATE_11MBPS);
+ else {
+ join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
+ join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS |
+ CONF_HW_BIT_RATE_12MBPS |
+ CONF_HW_BIT_RATE_24MBPS);
+ }
+
+ join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT);
+ join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
- join->beacon_interval = beacon_interval;
- join->dtim_interval = dtim_interval;
- join->bss_type = bss_type;
join->channel = wl->channel;
join->ssid_len = wl->ssid_len;
memcpy(join->ssid, wl->ssid, wl->ssid_len);
@@ -228,6 +257,10 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
+ /* reset TX security counters */
+ wl->tx_security_last_seq = 0;
+ wl->tx_security_seq_16 = 0;
+ wl->tx_security_seq_32 = 0;
ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
if (ret < 0) {
@@ -235,14 +268,13 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
goto out_free;
}
- timeout = msecs_to_jiffies(JOIN_TIMEOUT);
+ wl->joined = true;
/*
* ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
* simplify locking we just sleep instead, for now
*/
- if (wait)
- msleep(10);
+ msleep(10);
out_free:
kfree(join);
@@ -274,19 +306,20 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
if (answer) {
struct wl1271_command *cmd_answer;
+ u16 status;
/*
* The test command got in, we can read the answer.
* The answer would be a wl1271_command, where the
* parameter array contains the actual answer.
*/
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+ wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false);
cmd_answer = buf;
+ status = le16_to_cpu(cmd_answer->header.status);
- if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
- wl1271_error("TEST command answer error: %d",
- cmd_answer->header.status);
+ if (status != CMD_STATUS_SUCCESS)
+ wl1271_error("TEST command answer error: %d", status);
}
return 0;
@@ -307,10 +340,10 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
wl1271_debug(DEBUG_CMD, "cmd interrogate");
- acx->id = id;
+ acx->id = cpu_to_le16(id);
/* payload length, does not include any headers */
- acx->len = len - sizeof(*acx);
+ acx->len = cpu_to_le16(len - sizeof(*acx));
ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
if (ret < 0) {
@@ -319,12 +352,12 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
}
/* the interrogate command got in, we can read the answer */
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+ wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false);
acx = buf;
- if (acx->cmd.status != CMD_STATUS_SUCCESS)
+ if (le16_to_cpu(acx->cmd.status) != CMD_STATUS_SUCCESS)
wl1271_error("INTERROGATE command error: %d",
- acx->cmd.status);
+ le16_to_cpu(acx->cmd.status));
out:
return ret;
@@ -345,10 +378,10 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
wl1271_debug(DEBUG_CMD, "cmd configure");
- acx->id = id;
+ acx->id = cpu_to_le16(id);
/* payload length, does not include any headers */
- acx->len = len - sizeof(*acx);
+ acx->len = cpu_to_le16(len - sizeof(*acx));
ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len);
if (ret < 0) {
@@ -414,8 +447,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
int ret = 0;
/* FIXME: this should be in ps.c */
- ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
- wl->listen_int);
+ ret = wl1271_acx_wake_up_conditions(wl);
if (ret < 0) {
wl1271_error("couldn't set wake up conditions");
goto out;
@@ -433,7 +465,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
ps_params->send_null_data = 1;
ps_params->retries = 5;
ps_params->hang_over_period = 128;
- ps_params->null_data_rate = 1; /* 1 Mbps */
+ ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params));
@@ -464,8 +496,8 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
WARN_ON(len > MAX_READ_SIZE);
len = min_t(size_t, len, MAX_READ_SIZE);
- cmd->addr = addr;
- cmd->size = len;
+ cmd->addr = cpu_to_le32(addr);
+ cmd->size = cpu_to_le32(len);
ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
if (ret < 0) {
@@ -474,11 +506,11 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
}
/* the read command got in, we can now read the answer */
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+ wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false);
- if (cmd->header.status != CMD_STATUS_SUCCESS)
+ if (le16_to_cpu(cmd->header.status) != CMD_STATUS_SUCCESS)
wl1271_error("error in read command result: %d",
- cmd->header.status);
+ le16_to_cpu(cmd->header.status));
memcpy(answer, cmd->value, len);
@@ -488,14 +520,31 @@ out:
}
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
- u8 active_scan, u8 high_prio, u8 num_channels,
+ u8 active_scan, u8 high_prio, u8 band,
u8 probe_requests)
{
struct wl1271_cmd_trigger_scan_to *trigger = NULL;
struct wl1271_cmd_scan *params = NULL;
- int i, ret;
+ struct ieee80211_channel *channels;
+ int i, j, n_ch, ret;
u16 scan_options = 0;
+ u8 ieee_band;
+
+ if (band == WL1271_SCAN_BAND_2_4_GHZ)
+ ieee_band = IEEE80211_BAND_2GHZ;
+ else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled())
+ ieee_band = IEEE80211_BAND_2GHZ;
+ else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled())
+ ieee_band = IEEE80211_BAND_5GHZ;
+ else
+ return -EINVAL;
+
+ if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
+ return -EINVAL;
+
+ channels = wl->hw->wiphy->bands[ieee_band]->channels;
+ n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
if (wl->scanning)
return -EINVAL;
@@ -512,32 +561,43 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
scan_options |= WL1271_SCAN_OPT_PASSIVE;
if (high_prio)
scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
- params->params.scan_options = scan_options;
+ params->params.scan_options = cpu_to_le16(scan_options);
- params->params.num_channels = num_channels;
params->params.num_probe_requests = probe_requests;
- params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS);
+ /* Let the fw autodetect suitable tx_rate for probes */
+ params->params.tx_rate = 0;
params->params.tid_trigger = 0;
params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
- for (i = 0; i < num_channels; i++) {
- params->channels[i].min_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
- params->channels[i].max_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
- memset(&params->channels[i].bssid_lsb, 0xff, 4);
- memset(&params->channels[i].bssid_msb, 0xff, 2);
- params->channels[i].early_termination = 0;
- params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR;
- params->channels[i].channel = i + 1;
+ if (band == WL1271_SCAN_BAND_DUAL)
+ params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
+ else
+ params->params.band = band;
+
+ for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
+ if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
+ params->channels[j].min_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
+ params->channels[j].max_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
+ memset(&params->channels[j].bssid_lsb, 0xff, 4);
+ memset(&params->channels[j].bssid_msb, 0xff, 2);
+ params->channels[j].early_termination = 0;
+ params->channels[j].tx_power_att =
+ WL1271_SCAN_CURRENT_TX_PWR;
+ params->channels[j].channel = channels[i].hw_value;
+ j++;
+ }
}
+ params->params.num_channels = j;
+
if (len && ssid) {
params->params.ssid_len = len;
memcpy(params->params.ssid, ssid, len);
}
- ret = wl1271_cmd_build_probe_req(wl, ssid, len);
+ ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band);
if (ret < 0) {
wl1271_error("PROBE request template failed");
goto out;
@@ -562,6 +622,19 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
wl->scanning = true;
+ if (wl1271_11a_enabled()) {
+ wl->scan.state = band;
+ if (band == WL1271_SCAN_BAND_DUAL) {
+ wl->scan.active = active_scan;
+ wl->scan.high_prio = high_prio;
+ wl->scan.probe_requests = probe_requests;
+ if (len && ssid) {
+ wl->scan.ssid_len = len;
+ memcpy(wl->scan.ssid, ssid, len);
+ } else
+ wl->scan.ssid_len = 0;
+ }
+ }
ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
if (ret < 0) {
@@ -569,11 +642,12 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
goto out;
}
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params),
+ false);
- if (params->header.status != CMD_STATUS_SUCCESS) {
+ if (le16_to_cpu(params->header.status) != CMD_STATUS_SUCCESS) {
wl1271_error("Scan command error: %d",
- params->header.status);
+ le16_to_cpu(params->header.status));
wl->scanning = false;
ret = -EIO;
goto out;
@@ -603,9 +677,9 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
cmd->len = cpu_to_le16(buf_len);
cmd->template_type = template_id;
- cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
- cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT;
- cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT;
+ cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates);
+ cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit;
+ cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit;
if (buf)
memcpy(cmd->template_data, buf, buf_len);
@@ -623,30 +697,62 @@ out:
return ret;
}
-static int wl1271_build_basic_rates(char *rates)
+static int wl1271_build_basic_rates(char *rates, u8 band)
{
u8 index = 0;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
+ if (band == IEEE80211_BAND_2GHZ) {
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
+ } else if (band == IEEE80211_BAND_5GHZ) {
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
+ } else {
+ wl1271_error("build_basic_rates invalid band: %d", band);
+ }
return index;
}
-static int wl1271_build_extended_rates(char *rates)
+static int wl1271_build_extended_rates(char *rates, u8 band)
{
u8 index = 0;
- rates[index++] = IEEE80211_OFDM_RATE_6MB;
- rates[index++] = IEEE80211_OFDM_RATE_9MB;
- rates[index++] = IEEE80211_OFDM_RATE_12MB;
- rates[index++] = IEEE80211_OFDM_RATE_18MB;
- rates[index++] = IEEE80211_OFDM_RATE_24MB;
- rates[index++] = IEEE80211_OFDM_RATE_36MB;
- rates[index++] = IEEE80211_OFDM_RATE_48MB;
- rates[index++] = IEEE80211_OFDM_RATE_54MB;
+ if (band == IEEE80211_BAND_2GHZ) {
+ rates[index++] = IEEE80211_OFDM_RATE_6MB;
+ rates[index++] = IEEE80211_OFDM_RATE_9MB;
+ rates[index++] = IEEE80211_OFDM_RATE_12MB;
+ rates[index++] = IEEE80211_OFDM_RATE_18MB;
+ rates[index++] = IEEE80211_OFDM_RATE_24MB;
+ rates[index++] = IEEE80211_OFDM_RATE_36MB;
+ rates[index++] = IEEE80211_OFDM_RATE_48MB;
+ rates[index++] = IEEE80211_OFDM_RATE_54MB;
+ } else if (band == IEEE80211_BAND_5GHZ) {
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
+ } else {
+ wl1271_error("build_basic_rates invalid band: %d", band);
+ }
return index;
}
@@ -665,7 +771,8 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_NULLFUNC);
+ IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS);
return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template,
sizeof(template));
@@ -678,7 +785,10 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
memcpy(template.bssid, wl->bssid, ETH_ALEN);
memcpy(template.ta, wl->mac_addr, ETH_ALEN);
- template.aid = aid;
+
+ /* aid in PS-Poll has its two MSBs each set to 1 */
+ template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
+
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template,
@@ -686,12 +796,14 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
}
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
+int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
+ u8 band)
{
struct wl12xx_probe_req_template template;
struct wl12xx_ie_rates *rates;
char *ptr;
u16 size;
+ int ret;
ptr = (char *)&template;
size = sizeof(struct ieee80211_header);
@@ -713,20 +825,25 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
/* Basic Rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_SUPP_RATES;
- rates->header.len = wl1271_build_basic_rates(rates->rates);
+ rates->header.len = wl1271_build_basic_rates(rates->rates, band);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
/* Extended rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_EXT_SUPP_RATES;
- rates->header.len = wl1271_build_extended_rates(rates->rates);
+ rates->header.len = wl1271_build_extended_rates(rates->rates, band);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
- return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
- &template, size);
+ if (band == IEEE80211_BAND_2GHZ)
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ &template, size);
+ else
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ &template, size);
+ return ret;
}
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
@@ -743,7 +860,7 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
}
cmd->id = id;
- cmd->key_action = KEY_SET_ID;
+ cmd->key_action = cpu_to_le16(KEY_SET_ID);
cmd->key_type = KEY_WEP;
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
@@ -759,7 +876,8 @@ out:
}
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
- u8 key_size, const u8 *key, const u8 *addr)
+ u8 key_size, const u8 *key, const u8 *addr,
+ u32 tx_seq_32, u16 tx_seq_16)
{
struct wl1271_cmd_set_keys *cmd;
int ret = 0;
@@ -773,16 +891,18 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
if (key_type != KEY_WEP)
memcpy(cmd->addr, addr, ETH_ALEN);
- cmd->key_action = action;
+ cmd->key_action = cpu_to_le16(action);
cmd->key_size = key_size;
cmd->key_type = key_type;
+ cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
+ cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
+
/* we have only one SSID profile */
cmd->ssid_profile = 0;
cmd->id = id;
- /* FIXME: this is from wl1251, needs to be checked */
if (key_type == KEY_TKIP) {
/*
* We get the key in the following form:
@@ -811,3 +931,34 @@ out:
return ret;
}
+
+int wl1271_cmd_disconnect(struct wl1271 *wl)
+{
+ struct wl1271_cmd_disconnect *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd disconnect");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->rx_config_options = cpu_to_le32(wl->rx_config);
+ cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
+ /* disconnect reason is not used in immediate disconnections */
+ cmd->type = DISCONNECT_IMMEDIATE;
+
+ ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_error("failed to send disconnect command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index 951a8447a51..174b8209dbf 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -30,8 +30,7 @@
struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len);
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait);
+int wl1271_cmd_join(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
@@ -40,16 +39,19 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
- u8 active_scan, u8 high_prio, u8 num_channels,
+ u8 active_scan, u8 high_prio, u8 band,
u8 probe_requests);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len);
int wl1271_cmd_build_null_data(struct wl1271 *wl);
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len);
+int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
+ u8 band);
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
- u8 key_size, const u8 *key, const u8 *addr);
+ u8 key_size, const u8 *key, const u8 *addr,
+ u32 tx_seq_32, u16 tx_seq_16);
+int wl1271_cmd_disconnect(struct wl1271 *wl);
enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/
@@ -118,8 +120,8 @@ enum cmd_templ {
#define WL1271_CMD_TEMPL_MAX_SIZE 252
struct wl1271_cmd_header {
- u16 id;
- u16 status;
+ __le16 id;
+ __le16 status;
/* payload */
u8 data[0];
} __attribute__ ((packed));
@@ -172,17 +174,17 @@ struct cmd_read_write_memory {
struct wl1271_cmd_header header;
/* The address of the memory to read from or write to.*/
- u32 addr;
+ __le32 addr;
/* The amount of data in bytes to read from or write to the WiLink
* device.*/
- u32 size;
+ __le32 size;
/* The actual value read from or written to the Wilink. The source
of this field is the Host in WRITE command or the Wilink in READ
command. */
u8 value[MAX_READ_SIZE];
-};
+} __attribute__ ((packed));
#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -196,22 +198,23 @@ enum {
#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */
#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1
+#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10
struct wl1271_cmd_join {
struct wl1271_cmd_header header;
- u32 bssid_lsb;
- u16 bssid_msb;
- u16 beacon_interval; /* in TBTTs */
- u32 rx_config_options;
- u32 rx_filter_options;
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
+ __le16 beacon_interval; /* in TBTTs */
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
/*
* The target uses this field to determine the rate at
* which to transmit control frame responses (such as
* ACK or CTS frames).
*/
- u32 basic_rate_set;
+ __le32 basic_rate_set;
u8 dtim_interval;
/*
* bits 0-2: This bitwise field specifies the type
@@ -240,10 +243,10 @@ struct cmd_enabledisable_path {
struct wl1271_cmd_template_set {
struct wl1271_cmd_header header;
- u16 len;
+ __le16 len;
u8 template_type;
u8 index; /* relevant only for KLV_TEMPLATE type */
- u32 enabled_rates;
+ __le32 enabled_rates;
u8 short_retry_limit;
u8 long_retry_limit;
u8 aflags;
@@ -280,18 +283,13 @@ struct wl1271_cmd_ps_params {
* to power save mode.
*/
u8 hang_over_period;
- u32 null_data_rate;
+ __le32 null_data_rate;
} __attribute__ ((packed));
/* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4
#define MAX_KEY_SIZE 32
-/* When set, disable HW encryption */
-#define DF_ENCRYPTION_DISABLE 0x01
-/* When set, disable HW decryption */
-#define DF_SNIFF_MODE_ENABLE 0x80
-
enum wl1271_cmd_key_action {
KEY_ADD_OR_REPLACE = 1,
KEY_REMOVE = 2,
@@ -316,9 +314,9 @@ struct wl1271_cmd_set_keys {
u8 addr[ETH_ALEN];
/* key_action_e */
- u16 key_action;
+ __le16 key_action;
- u16 reserved_1;
+ __le16 reserved_1;
/* key size in bytes */
u8 key_size;
@@ -334,8 +332,8 @@ struct wl1271_cmd_set_keys {
u8 id;
u8 reserved_2[6];
u8 key[MAX_KEY_SIZE];
- u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+ __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+ __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
} __attribute__ ((packed));
@@ -347,19 +345,22 @@ struct wl1271_cmd_set_keys {
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
+#define WL1271_SCAN_BAND_2_4_GHZ 0
+#define WL1271_SCAN_BAND_5_GHZ 1
+#define WL1271_SCAN_BAND_DUAL 2
struct basic_scan_params {
- u32 rx_config_options;
- u32 rx_filter_options;
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
/* Scan option flags (WL1271_SCAN_OPT_*) */
- u16 scan_options;
+ __le16 scan_options;
/* Number of scan channels in the list (maximum 30) */
u8 num_channels;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 num_probe_requests;
/* Rate bit field for sending the probes */
- u32 tx_rate;
+ __le32 tx_rate;
u8 tid_trigger;
u8 ssid_len;
/* in order to align */
@@ -374,10 +375,10 @@ struct basic_scan_params {
struct basic_scan_channel_params {
/* Duration in TU to wait for frames on a channel for active scan */
- u32 min_duration;
- u32 max_duration;
- u32 bssid_lsb;
- u16 bssid_msb;
+ __le32 min_duration;
+ __le32 max_duration;
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
u8 early_termination;
u8 tx_power_att;
u8 channel;
@@ -397,13 +398,13 @@ struct wl1271_cmd_scan {
struct wl1271_cmd_trigger_scan_to {
struct wl1271_cmd_header header;
- u32 timeout;
-};
+ __le32 timeout;
+} __attribute__ ((packed));
struct wl1271_cmd_test_header {
u8 id;
u8 padding[3];
-};
+} __attribute__ ((packed));
enum wl1271_channel_tune_bands {
WL1271_CHANNEL_TUNE_BAND_2_4,
@@ -425,7 +426,7 @@ struct wl1271_cmd_cal_channel_tune {
u8 band;
u8 channel;
- u16 radio_status;
+ __le16 radio_status;
} __attribute__ ((packed));
struct wl1271_cmd_cal_update_ref_point {
@@ -433,8 +434,8 @@ struct wl1271_cmd_cal_update_ref_point {
struct wl1271_cmd_test_header test;
- s32 ref_power;
- s32 ref_detector;
+ __le32 ref_power;
+ __le32 ref_detector;
u8 sub_band;
u8 padding[3];
} __attribute__ ((packed));
@@ -449,16 +450,42 @@ struct wl1271_cmd_cal_p2g {
struct wl1271_cmd_test_header test;
- u16 len;
+ __le16 len;
u8 buf[MAX_TLV_LENGTH];
u8 type;
u8 padding;
- s16 radio_status;
+ __le16 radio_status;
u8 nvs_version[MAX_NVS_VERSION_LENGTH];
u8 sub_band_mask;
u8 padding2;
} __attribute__ ((packed));
+
+/*
+ * There are three types of disconnections:
+ *
+ * DISCONNECT_IMMEDIATE: the fw doesn't send any frames
+ * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason
+ * we have passed
+ * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason
+ * we have passed
+ */
+enum wl1271_disconnect_type {
+ DISCONNECT_IMMEDIATE,
+ DISCONNECT_DEAUTH,
+ DISCONNECT_DISASSOC
+};
+
+struct wl1271_cmd_disconnect {
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
+
+ __le16 reason;
+ u8 type;
+
+ u8 padding;
+} __attribute__ ((packed));
+
#endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h
new file mode 100644
index 00000000000..061d47520a3
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_conf.h
@@ -0,0 +1,911 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_CONF_H__
+#define __WL1271_CONF_H__
+
+enum {
+ CONF_HW_BIT_RATE_1MBPS = BIT(0),
+ CONF_HW_BIT_RATE_2MBPS = BIT(1),
+ CONF_HW_BIT_RATE_5_5MBPS = BIT(2),
+ CONF_HW_BIT_RATE_6MBPS = BIT(3),
+ CONF_HW_BIT_RATE_9MBPS = BIT(4),
+ CONF_HW_BIT_RATE_11MBPS = BIT(5),
+ CONF_HW_BIT_RATE_12MBPS = BIT(6),
+ CONF_HW_BIT_RATE_18MBPS = BIT(7),
+ CONF_HW_BIT_RATE_22MBPS = BIT(8),
+ CONF_HW_BIT_RATE_24MBPS = BIT(9),
+ CONF_HW_BIT_RATE_36MBPS = BIT(10),
+ CONF_HW_BIT_RATE_48MBPS = BIT(11),
+ CONF_HW_BIT_RATE_54MBPS = BIT(12),
+ CONF_HW_BIT_RATE_MCS_0 = BIT(13),
+ CONF_HW_BIT_RATE_MCS_1 = BIT(14),
+ CONF_HW_BIT_RATE_MCS_2 = BIT(15),
+ CONF_HW_BIT_RATE_MCS_3 = BIT(16),
+ CONF_HW_BIT_RATE_MCS_4 = BIT(17),
+ CONF_HW_BIT_RATE_MCS_5 = BIT(18),
+ CONF_HW_BIT_RATE_MCS_6 = BIT(19),
+ CONF_HW_BIT_RATE_MCS_7 = BIT(20)
+};
+
+enum {
+ CONF_HW_RATE_INDEX_1MBPS = 0,
+ CONF_HW_RATE_INDEX_2MBPS = 1,
+ CONF_HW_RATE_INDEX_5_5MBPS = 2,
+ CONF_HW_RATE_INDEX_6MBPS = 3,
+ CONF_HW_RATE_INDEX_9MBPS = 4,
+ CONF_HW_RATE_INDEX_11MBPS = 5,
+ CONF_HW_RATE_INDEX_12MBPS = 6,
+ CONF_HW_RATE_INDEX_18MBPS = 7,
+ CONF_HW_RATE_INDEX_22MBPS = 8,
+ CONF_HW_RATE_INDEX_24MBPS = 9,
+ CONF_HW_RATE_INDEX_36MBPS = 10,
+ CONF_HW_RATE_INDEX_48MBPS = 11,
+ CONF_HW_RATE_INDEX_54MBPS = 12,
+ CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
+};
+
+struct conf_sg_settings {
+ /*
+ * Defines the PER threshold in PPM of the BT voice of which reaching
+ * this value will trigger raising the priority of the BT voice by
+ * the BT IP until next NFS sample interval time as defined in
+ * nfs_sample_interval.
+ *
+ * Unit: PER value in PPM (parts per million)
+ * #Error_packets / #Total_packets
+
+ * Range: u32
+ */
+ u32 per_threshold;
+
+ /*
+ * This value is an absolute time in micro-seconds to limit the
+ * maximum scan duration compensation while in SG
+ */
+ u32 max_scan_compensation_time;
+
+ /* Defines the PER threshold of the BT voice of which reaching this
+ * value will trigger raising the priority of the BT voice until next
+ * NFS sample interval time as defined in sample_interval.
+ *
+ * Unit: msec
+ * Range: 1-65000
+ */
+ u16 nfs_sample_interval;
+
+ /*
+ * Defines the load ratio for the BT.
+ * The WLAN ratio is: 100 - load_ratio
+ *
+ * Unit: Percent
+ * Range: 0-100
+ */
+ u8 load_ratio;
+
+ /*
+ * true - Co-ex is allowed to enter/exit P.S automatically and
+ * transparently to the host
+ *
+ * false - Co-ex is disallowed to enter/exit P.S and will trigger an
+ * event to the host to notify for the need to enter/exit P.S
+ * due to BT change state
+ *
+ */
+ u8 auto_ps_mode;
+
+ /*
+ * This parameter defines the compensation percentage of num of probe
+ * requests in case scan is initiated during BT voice/BT ACL
+ * guaranteed link.
+ *
+ * Unit: Percent
+ * Range: 0-255 (0 - No compensation)
+ */
+ u8 probe_req_compensation;
+
+ /*
+ * This parameter defines the compensation percentage of scan window
+ * size in case scan is initiated during BT voice/BT ACL Guaranteed
+ * link.
+ *
+ * Unit: Percent
+ * Range: 0-255 (0 - No compensation)
+ */
+ u8 scan_window_compensation;
+
+ /*
+ * Defines the antenna configuration.
+ *
+ * Range: 0 - Single Antenna; 1 - Dual Antenna
+ */
+ u8 antenna_config;
+
+ /*
+ * The percent out of the Max consecutive beacon miss roaming trigger
+ * which is the threshold for raising the priority of beacon
+ * reception.
+ *
+ * Range: 1-100
+ * N = MaxConsecutiveBeaconMiss
+ * P = coexMaxConsecutiveBeaconMissPrecent
+ * Threshold = MIN( N-1, round(N * P / 100))
+ */
+ u8 beacon_miss_threshold;
+
+ /*
+ * The RX rate threshold below which rate adaptation is assumed to be
+ * occurring at the AP which will raise priority for ACTIVE_RX and RX
+ * SP.
+ *
+ * Range: HW_BIT_RATE_*
+ */
+ u32 rate_adaptation_threshold;
+
+ /*
+ * The SNR above which the RX rate threshold indicating AP rate
+ * adaptation is valid
+ *
+ * Range: -128 - 127
+ */
+ s8 rate_adaptation_snr;
+};
+
+enum conf_rx_queue_type {
+ CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */
+ CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */
+};
+
+struct conf_rx_settings {
+ /*
+ * The maximum amount of time, in TU, before the
+ * firmware discards the MSDU.
+ *
+ * Range: 0 - 0xFFFFFFFF
+ */
+ u32 rx_msdu_life_time;
+
+ /*
+ * Packet detection threshold in the PHY.
+ *
+ * FIXME: details unknown.
+ */
+ u32 packet_detection_threshold;
+
+ /*
+ * The longest time the STA will wait to receive traffic from the AP
+ * after a PS-poll has been transmitted.
+ *
+ * Range: 0 - 200000
+ */
+ u16 ps_poll_timeout;
+ /*
+ * The longest time the STA will wait to receive traffic from the AP
+ * after a frame has been sent from an UPSD enabled queue.
+ *
+ * Range: 0 - 200000
+ */
+ u16 upsd_timeout;
+
+ /*
+ * The number of octets in an MPDU, below which an RTS/CTS
+ * handshake is not performed.
+ *
+ * Range: 0 - 4096
+ */
+ u16 rts_threshold;
+
+ /*
+ * The RX Clear Channel Assessment threshold in the PHY
+ * (the energy threshold).
+ *
+ * Range: ENABLE_ENERGY_D == 0x140A
+ * DISABLE_ENERGY_D == 0xFFEF
+ */
+ u16 rx_cca_threshold;
+
+ /*
+ * Occupied Rx mem-blocks number which requires interrupting the host
+ * (0 = no buffering, 0xffff = disabled).
+ *
+ * Range: u16
+ */
+ u16 irq_blk_threshold;
+
+ /*
+ * Rx packets number which requires interrupting the host
+ * (0 = no buffering).
+ *
+ * Range: u16
+ */
+ u16 irq_pkt_threshold;
+
+ /*
+ * Max time in msec the FW may delay RX-Complete interrupt.
+ *
+ * Range: 1 - 100
+ */
+ u16 irq_timeout;
+
+ /*
+ * The RX queue type.
+ *
+ * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY,
+ */
+ u8 queue_type;
+};
+
+#define CONF_TX_MAX_RATE_CLASSES 8
+
+#define CONF_TX_RATE_MASK_UNSPECIFIED 0
+#define CONF_TX_RATE_MASK_ALL 0x1eff
+#define CONF_TX_RATE_RETRY_LIMIT 10
+
+struct conf_tx_rate_class {
+
+ /*
+ * The rates enabled for this rate class.
+ *
+ * Range: CONF_HW_BIT_RATE_* bit mask
+ */
+ u32 enabled_rates;
+
+ /*
+ * The dot11 short retry limit used for TX retries.
+ *
+ * Range: u8
+ */
+ u8 short_retry_limit;
+
+ /*
+ * The dot11 long retry limit used for TX retries.
+ *
+ * Range: u8
+ */
+ u8 long_retry_limit;
+
+ /*
+ * Flags controlling the attributes of TX transmission.
+ *
+ * Range: bit 0: Truncate - when set, FW attempts to send a frame stop
+ * when the total valid per-rate attempts have
+ * been exhausted; otherwise transmissions
+ * will continue at the lowest available rate
+ * until the appropriate one of the
+ * short_retry_limit, long_retry_limit,
+ * dot11_max_transmit_msdu_life_time, or
+ * max_tx_life_time, is exhausted.
+ * 1: Preamble Override - indicates if the preamble type
+ * should be used in TX.
+ * 2: Preamble Type - the type of the preamble to be used by
+ * the policy (0 - long preamble, 1 - short preamble.
+ */
+ u8 aflags;
+};
+
+#define CONF_TX_MAX_AC_COUNT 4
+
+/* Slot number setting to start transmission at PIFS interval */
+#define CONF_TX_AIFS_PIFS 1
+/* Slot number setting to start transmission at DIFS interval normal
+ * DCF access */
+#define CONF_TX_AIFS_DIFS 2
+
+
+enum conf_tx_ac {
+ CONF_TX_AC_BE = 0, /* best effort / legacy */
+ CONF_TX_AC_BK = 1, /* background */
+ CONF_TX_AC_VI = 2, /* video */
+ CONF_TX_AC_VO = 3, /* voice */
+ CONF_TX_AC_CTS2SELF = 4, /* fictious AC, follows AC_VO */
+ CONF_TX_AC_ANY_TID = 0x1f
+};
+
+struct conf_tx_ac_category {
+ /*
+ * The AC class identifier.
+ *
+ * Range: enum conf_tx_ac
+ */
+ u8 ac;
+
+ /*
+ * The contention window minimum size (in slots) for the access
+ * class.
+ *
+ * Range: u8
+ */
+ u8 cw_min;
+
+ /*
+ * The contention window maximum size (in slots) for the access
+ * class.
+ *
+ * Range: u8
+ */
+ u16 cw_max;
+
+ /*
+ * The AIF value (in slots) for the access class.
+ *
+ * Range: u8
+ */
+ u8 aifsn;
+
+ /*
+ * The TX Op Limit (in microseconds) for the access class.
+ *
+ * Range: u16
+ */
+ u16 tx_op_limit;
+};
+
+#define CONF_TX_MAX_TID_COUNT 7
+
+enum {
+ CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
+ CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/
+ CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/
+};
+
+enum {
+ CONF_PS_SCHEME_LEGACY = 0,
+ CONF_PS_SCHEME_UPSD_TRIGGER = 1,
+ CONF_PS_SCHEME_LEGACY_PSPOLL = 2,
+ CONF_PS_SCHEME_SAPSD = 3,
+};
+
+enum {
+ CONF_ACK_POLICY_LEGACY = 0,
+ CONF_ACK_POLICY_NO_ACK = 1,
+ CONF_ACK_POLICY_BLOCK = 2,
+};
+
+
+struct conf_tx_tid {
+ u8 queue_id;
+ u8 channel_type;
+ u8 tsid;
+ u8 ps_scheme;
+ u8 ack_policy;
+ u32 apsd_conf[2];
+};
+
+struct conf_tx_settings {
+ /*
+ * The TX ED value for TELEC Enable/Disable.
+ *
+ * Range: 0, 1
+ */
+ u8 tx_energy_detection;
+
+ /*
+ * Configuration for rate classes for TX (currently only one
+ * rate class supported.)
+ */
+ struct conf_tx_rate_class rc_conf;
+
+ /*
+ * Configuration for access categories for TX rate control.
+ */
+ u8 ac_conf_count;
+ struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];
+
+ /*
+ * Configuration for TID parameters.
+ */
+ u8 tid_conf_count;
+ struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT];
+
+ /*
+ * The TX fragmentation threshold.
+ *
+ * Range: u16
+ */
+ u16 frag_threshold;
+
+ /*
+ * Max time in msec the FW may delay frame TX-Complete interrupt.
+ *
+ * Range: u16
+ */
+ u16 tx_compl_timeout;
+
+ /*
+ * Completed TX packet count which requires to issue the TX-Complete
+ * interrupt.
+ *
+ * Range: u16
+ */
+ u16 tx_compl_threshold;
+
+};
+
+enum {
+ CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/
+ CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/
+ CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */
+ CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */
+ CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F
+};
+
+#define CONF_MAX_BCN_FILT_IE_COUNT 32
+
+#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0)
+#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1)
+
+#define CONF_BCN_IE_OUI_LEN 3
+#define CONF_BCN_IE_VER_LEN 2
+
+struct conf_bcn_filt_rule {
+ /*
+ * IE number to which to associate a rule.
+ *
+ * Range: u8
+ */
+ u8 ie;
+
+ /*
+ * Rule to associate with the specific ie.
+ *
+ * Range: CONF_BCN_RULE_PASS_ON_*
+ */
+ u8 rule;
+
+ /*
+ * OUI for the vendor specifie IE (221)
+ */
+ u8 oui[CONF_BCN_IE_OUI_LEN];
+
+ /*
+ * Type for the vendor specifie IE (221)
+ */
+ u8 type;
+
+ /*
+ * Version for the vendor specifie IE (221)
+ */
+ u8 version[CONF_BCN_IE_VER_LEN];
+};
+
+#define CONF_MAX_RSSI_SNR_TRIGGERS 8
+
+enum {
+ CONF_TRIG_METRIC_RSSI_BEACON = 0,
+ CONF_TRIG_METRIC_RSSI_DATA,
+ CONF_TRIG_METRIC_SNR_BEACON,
+ CONF_TRIG_METRIC_SNR_DATA
+};
+
+enum {
+ CONF_TRIG_EVENT_TYPE_LEVEL = 0,
+ CONF_TRIG_EVENT_TYPE_EDGE
+};
+
+enum {
+ CONF_TRIG_EVENT_DIR_LOW = 0,
+ CONF_TRIG_EVENT_DIR_HIGH,
+ CONF_TRIG_EVENT_DIR_BIDIR
+};
+
+
+struct conf_sig_trigger {
+ /*
+ * The RSSI / SNR threshold value.
+ *
+ * FIXME: what is the range?
+ */
+ s16 threshold;
+
+ /*
+ * Minimum delay between two trigger events for this trigger in ms.
+ *
+ * Range: 0 - 60000
+ */
+ u16 pacing;
+
+ /*
+ * The measurement data source for this trigger.
+ *
+ * Range: CONF_TRIG_METRIC_*
+ */
+ u8 metric;
+
+ /*
+ * The trigger type of this trigger.
+ *
+ * Range: CONF_TRIG_EVENT_TYPE_*
+ */
+ u8 type;
+
+ /*
+ * The direction of the trigger.
+ *
+ * Range: CONF_TRIG_EVENT_DIR_*
+ */
+ u8 direction;
+
+ /*
+ * Hysteresis range of the trigger around the threshold (in dB)
+ *
+ * Range: u8
+ */
+ u8 hysteresis;
+
+ /*
+ * Index of the trigger rule.
+ *
+ * Range: 0 - CONF_MAX_RSSI_SNR_TRIGGERS-1
+ */
+ u8 index;
+
+ /*
+ * Enable / disable this rule (to use for clearing rules.)
+ *
+ * Range: 1 - Enabled, 2 - Not enabled
+ */
+ u8 enable;
+};
+
+struct conf_sig_weights {
+
+ /*
+ * RSSI from beacons average weight.
+ *
+ * Range: u8
+ */
+ u8 rssi_bcn_avg_weight;
+
+ /*
+ * RSSI from data average weight.
+ *
+ * Range: u8
+ */
+ u8 rssi_pkt_avg_weight;
+
+ /*
+ * SNR from beacons average weight.
+ *
+ * Range: u8
+ */
+ u8 snr_bcn_avg_weight;
+
+ /*
+ * SNR from data average weight.
+ *
+ * Range: u8
+ */
+ u8 snr_pkt_avg_weight;
+};
+
+enum conf_bcn_filt_mode {
+ CONF_BCN_FILT_MODE_DISABLED = 0,
+ CONF_BCN_FILT_MODE_ENABLED = 1
+};
+
+enum conf_bet_mode {
+ CONF_BET_MODE_DISABLE = 0,
+ CONF_BET_MODE_ENABLE = 1,
+};
+
+struct conf_conn_settings {
+ /*
+ * Firmware wakeup conditions configuration. The host may set only
+ * one bit.
+ *
+ * Range: CONF_WAKE_UP_EVENT_*
+ */
+ u8 wake_up_event;
+
+ /*
+ * Listen interval for beacons or Dtims.
+ *
+ * Range: 0 for beacon and Dtim wakeup
+ * 1-10 for x Dtims
+ * 1-255 for x beacons
+ */
+ u8 listen_interval;
+
+ /*
+ * Enable or disable the beacon filtering.
+ *
+ * Range: CONF_BCN_FILT_MODE_*
+ */
+ enum conf_bcn_filt_mode bcn_filt_mode;
+
+ /*
+ * Configure Beacon filter pass-thru rules.
+ */
+ u8 bcn_filt_ie_count;
+ struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT];
+
+ /*
+ * The number of consequtive beacons to lose, before the firmware
+ * becomes out of synch.
+ *
+ * Range: u32
+ */
+ u32 synch_fail_thold;
+
+ /*
+ * After out-of-synch, the number of TU's to wait without a further
+ * received beacon (or probe response) before issuing the BSS_EVENT_LOSE
+ * event.
+ *
+ * Range: u32
+ */
+ u32 bss_lose_timeout;
+
+ /*
+ * Beacon receive timeout.
+ *
+ * Range: u32
+ */
+ u32 beacon_rx_timeout;
+
+ /*
+ * Broadcast receive timeout.
+ *
+ * Range: u32
+ */
+ u32 broadcast_timeout;
+
+ /*
+ * Enable/disable reception of broadcast packets in power save mode
+ *
+ * Range: 1 - enable, 0 - disable
+ */
+ u8 rx_broadcast_in_ps;
+
+ /*
+ * Consequtive PS Poll failures before sending event to driver
+ *
+ * Range: u8
+ */
+ u8 ps_poll_threshold;
+
+ /*
+ * Configuration of signal (rssi/snr) triggers.
+ */
+ u8 sig_trigger_count;
+ struct conf_sig_trigger sig_trigger[CONF_MAX_RSSI_SNR_TRIGGERS];
+
+ /*
+ * Configuration of signal average weights.
+ */
+ struct conf_sig_weights sig_weights;
+
+ /*
+ * Specifies if beacon early termination procedure is enabled or
+ * disabled.
+ *
+ * Range: CONF_BET_MODE_*
+ */
+ u8 bet_enable;
+
+ /*
+ * Specifies the maximum number of consecutive beacons that may be
+ * early terminated. After this number is reached at least one full
+ * beacon must be correctly received in FW before beacon ET
+ * resumes.
+ *
+ * Range 0 - 255
+ */
+ u8 bet_max_consecutive;
+};
+
+#define CONF_SR_ERR_TBL_MAX_VALUES 14
+
+struct conf_mart_reflex_err_table {
+ /*
+ * Length of the error table values table.
+ *
+ * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES
+ */
+ u8 len;
+
+ /*
+ * Smart Reflex error table upper limit.
+ *
+ * Range: s8
+ */
+ s8 upper_limit;
+
+ /*
+ * Smart Reflex error table values.
+ *
+ * Range: s8
+ */
+ s8 values[CONF_SR_ERR_TBL_MAX_VALUES];
+};
+
+enum {
+ CONF_REF_CLK_19_2_E,
+ CONF_REF_CLK_26_E,
+ CONF_REF_CLK_38_4_E,
+ CONF_REF_CLK_52_E
+};
+
+enum single_dual_band_enum {
+ CONF_SINGLE_BAND,
+ CONF_DUAL_BAND
+};
+
+struct conf_general_parms {
+ /*
+ * RF Reference Clock type / speed
+ *
+ * Range: CONF_REF_CLK_*
+ */
+ u8 ref_clk;
+
+ /*
+ * Settling time of the reference clock after boot.
+ *
+ * Range: u8
+ */
+ u8 settling_time;
+
+ /*
+ * Flag defining whether clock is valid on wakeup.
+ *
+ * Range: 0 - not valid on wakeup, 1 - valid on wakeup
+ */
+ u8 clk_valid_on_wakeup;
+
+ /*
+ * DC-to-DC mode.
+ *
+ * Range: Unknown
+ */
+ u8 dc2dcmode;
+
+ /*
+ * Flag defining whether used as single or dual-band.
+ *
+ * Range: CONF_SINGLE_BAND, CONF_DUAL_BAND
+ */
+ u8 single_dual_band;
+
+ /*
+ * TX bip fem autodetect flag.
+ *
+ * Range: Unknown
+ */
+ u8 tx_bip_fem_autodetect;
+
+ /*
+ * TX bip gem manufacturer.
+ *
+ * Range: Unknown
+ */
+ u8 tx_bip_fem_manufacturer;
+
+ /*
+ * Settings flags.
+ *
+ * Range: Unknown
+ */
+ u8 settings;
+};
+
+#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
+#define CONF_NUMBER_OF_SUB_BANDS_5 7
+#define CONF_NUMBER_OF_RATE_GROUPS 6
+#define CONF_NUMBER_OF_CHANNELS_2_4 14
+#define CONF_NUMBER_OF_CHANNELS_5 35
+
+struct conf_radio_parms {
+ /*
+ * Static radio parameters for 2.4GHz
+ *
+ * Range: unknown
+ */
+ u8 rx_trace_loss;
+ u8 tx_trace_loss;
+ s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
+
+ /*
+ * Static radio parameters for 5GHz
+ *
+ * Range: unknown
+ */
+ u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
+
+ /*
+ * Dynamic radio parameters for 2.4GHz
+ *
+ * Range: unknown
+ */
+ s16 tx_ref_pd_voltage;
+ s8 tx_ref_power;
+ s8 tx_offset_db;
+
+ s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
+
+ s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
+
+ u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
+ u8 rx_fem_insertion_loss;
+
+ /*
+ * Dynamic radio parameters for 5GHz
+ *
+ * Range: unknown
+ */
+ s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
+
+ s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
+
+ s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
+ s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
+
+ /* FIXME: this is inconsistent with the types for 2.4GHz */
+ s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+};
+
+#define CONF_SR_ERR_TBL_COUNT 3
+
+struct conf_init_settings {
+ /*
+ * Configure Smart Reflex error table values.
+ */
+ struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT];
+
+ /*
+ * Smart Reflex enable flag.
+ *
+ * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled
+ */
+ u8 sr_enable;
+
+ /*
+ * Configure general parameters.
+ */
+ struct conf_general_parms genparam;
+
+ /*
+ * Configure radio parameters.
+ */
+ struct conf_radio_parms radioparam;
+
+};
+
+struct conf_drv_settings {
+ struct conf_sg_settings sg;
+ struct conf_rx_settings rx;
+ struct conf_tx_settings tx;
+ struct conf_conn_settings conn;
+ struct conf_init_settings init;
+};
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index f3afd4a6ff3..31d396ba918 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -26,20 +26,45 @@
#include "wl1271_spi.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
+#include "wl12xx_80211.h"
static int wl1271_event_scan_complete(struct wl1271 *wl,
struct event_mailbox *mbox)
{
+ int size = sizeof(struct wl12xx_probe_req_template);
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
mbox->scheduled_scan_status);
if (wl->scanning) {
- mutex_unlock(&wl->mutex);
- ieee80211_scan_completed(wl->hw, false);
- mutex_lock(&wl->mutex);
- wl->scanning = false;
+ if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
+ wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ NULL, size);
+ /* 2.4 GHz band scanned, scan 5 GHz band, pretend
+ * to the wl1271_cmd_scan function that we are not
+ * scanning as it checks that.
+ */
+ wl->scanning = false;
+ wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
+ wl->scan.active,
+ wl->scan.high_prio,
+ WL1271_SCAN_BAND_5_GHZ,
+ wl->scan.probe_requests);
+ } else {
+ if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
+ wl1271_cmd_template_set(wl,
+ CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ NULL, size);
+ else
+ wl1271_cmd_template_set(wl,
+ CMD_TEMPL_CFG_PROBE_REQ_5,
+ NULL, size);
+
+ mutex_unlock(&wl->mutex);
+ ieee80211_scan_completed(wl->hw, false);
+ mutex_lock(&wl->mutex);
+ wl->scanning = false;
+ }
}
-
return 0;
}
@@ -57,7 +82,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_event_mbox_dump(mbox);
- vector = mbox->events_vector & ~(mbox->events_mask);
+ vector = le32_to_cpu(mbox->events_vector);
+ vector &= ~(le32_to_cpu(mbox->events_mask));
wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
@@ -66,14 +92,16 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
return ret;
}
- if (vector & BSS_LOSE_EVENT_ID) {
+ /*
+ * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
+ * filtering) is enabled. Without PSM, the stack will receive all
+ * beacons and can detect beacon loss by itself.
+ */
+ if (vector & BSS_LOSE_EVENT_ID && wl->psm) {
wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
- if (wl->psm_requested && wl->psm) {
- ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
- if (ret < 0)
- return ret;
- }
+ /* indicate to the stack, that beacons have been lost */
+ ieee80211_beacon_loss(wl->vif);
}
return 0;
@@ -92,14 +120,14 @@ int wl1271_event_unmask(struct wl1271 *wl)
void wl1271_event_mbox_config(struct wl1271 *wl)
{
- wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
{
struct event_mailbox mbox;
int ret;
@@ -110,8 +138,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return -EINVAL;
/* first we read the mbox descriptor */
- wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
- sizeof(struct event_mailbox));
+ wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ sizeof(struct event_mailbox), false);
/* process the descriptor */
ret = wl1271_event_process(wl, &mbox);
@@ -119,7 +147,9 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return ret;
/* then we let the firmware know it can go on...*/
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+ if (do_ack)
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG,
+ INTR_TRIG_EVENT_ACK);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h
index 2cdce7c34bf..3ab53d331f1 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.h
+++ b/drivers/net/wireless/wl12xx/wl1271_event.h
@@ -66,33 +66,33 @@ enum {
struct event_debug_report {
u8 debug_event_id;
u8 num_params;
- u16 pad;
- u32 report_1;
- u32 report_2;
- u32 report_3;
+ __le16 pad;
+ __le32 report_1;
+ __le32 report_2;
+ __le32 report_3;
} __attribute__ ((packed));
#define NUM_OF_RSSI_SNR_TRIGGERS 8
struct event_mailbox {
- u32 events_vector;
- u32 events_mask;
- u32 reserved_1;
- u32 reserved_2;
+ __le32 events_vector;
+ __le32 events_mask;
+ __le32 reserved_1;
+ __le32 reserved_2;
u8 dbg_event_id;
u8 num_relevant_params;
- u16 reserved_3;
- u32 event_report_p1;
- u32 event_report_p2;
- u32 event_report_p3;
+ __le16 reserved_3;
+ __le32 event_report_p1;
+ __le32 event_report_p2;
+ __le32 event_report_p3;
u8 number_of_scan_results;
u8 scan_tag;
u8 reserved_4[2];
- u32 compl_scheduled_scan_status;
+ __le32 compl_scheduled_scan_status;
- u16 scheduled_scan_attended_channels;
+ __le16 scheduled_scan_attended_channels;
u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
@@ -105,6 +105,6 @@ struct event_mailbox {
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c
index 490df217605..417b4152feb 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/wl1271_init.c
@@ -59,6 +59,14 @@ static int wl1271_init_templates_config(struct wl1271 *wl)
if (ret < 0)
return ret;
+ if (wl1271_11a_enabled()) {
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ NULL,
+ sizeof(struct wl12xx_probe_req_template));
+ if (ret < 0)
+ return ret;
+ }
+
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template));
if (ret < 0)
@@ -94,7 +102,7 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
{
int ret;
- ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+ ret = wl1271_acx_rx_msdu_life_time(wl);
if (ret < 0)
return ret;
@@ -117,7 +125,7 @@ static int wl1271_init_phy_config(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_group_address_tbl(wl);
+ ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0);
if (ret < 0)
return ret;
@@ -125,7 +133,7 @@ static int wl1271_init_phy_config(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+ ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold);
if (ret < 0)
return ret;
@@ -136,7 +144,8 @@ static int wl1271_init_beacon_filter(struct wl1271 *wl)
{
int ret;
- ret = wl1271_acx_beacon_filter_opt(wl);
+ /* disable beacon filtering at this stage */
+ ret = wl1271_acx_beacon_filter_opt(wl, false);
if (ret < 0)
return ret;
@@ -187,6 +196,7 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
static int wl1271_init_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms *gen_parms;
+ struct conf_general_parms *g = &wl->conf.init.genparam;
int ret;
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
@@ -195,15 +205,14 @@ static int wl1271_init_general_parms(struct wl1271 *wl)
gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM;
- gen_parms->ref_clk = REF_CLK_38_4_E;
- /* FIXME: magic numbers */
- gen_parms->settling_time = 5;
- gen_parms->clk_valid_on_wakeup = 0;
- gen_parms->dc2dcmode = 0;
- gen_parms->single_dual_band = 0;
- gen_parms->tx_bip_fem_autodetect = 1;
- gen_parms->tx_bip_fem_manufacturer = 1;
- gen_parms->settings = 1;
+ gen_parms->ref_clk = g->ref_clk;
+ gen_parms->settling_time = g->settling_time;
+ gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup;
+ gen_parms->dc2dcmode = g->dc2dcmode;
+ gen_parms->single_dual_band = g->single_dual_band;
+ gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect;
+ gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
+ gen_parms->settings = g->settings;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0) {
@@ -217,32 +226,9 @@ static int wl1271_init_general_parms(struct wl1271 *wl)
static int wl1271_init_radio_parms(struct wl1271 *wl)
{
- /*
- * FIXME: All these magic numbers should be moved to some place where
- * they can be configured (separate file?)
- */
-
struct wl1271_radio_parms *radio_parms;
- int ret;
- u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00,
- 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 };
-
- u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 };
- u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 };
-
- u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x22, 0x50,
- 0x22, 0x50 };
-
- u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x20, 0x50,
- 0x20, 0x50 };
-
- u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
- u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 };
+ struct conf_radio_parms *r = &wl->conf.init.radioparam;
+ int i, ret;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
@@ -251,33 +237,59 @@ static int wl1271_init_radio_parms(struct wl1271 *wl)
radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* Static radio parameters */
- radio_parms->rx_trace_loss = 10;
- radio_parms->tx_trace_loss = 10;
- memcpy(radio_parms->rx_rssi_and_proc_compens, compensation,
- sizeof(compensation));
-
- /* We don't set the 5GHz -- N/A */
+ radio_parms->rx_trace_loss = r->rx_trace_loss;
+ radio_parms->tx_trace_loss = r->tx_trace_loss;
+ memcpy(radio_parms->rx_rssi_and_proc_compens,
+ r->rx_rssi_and_proc_compens,
+ CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
+
+ memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->rx_rssi_and_proc_compens_5,
+ r->rx_rssi_and_proc_compens_5,
+ CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
/* Dynamic radio parameters */
- radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e);
- radio_parms->tx_ref_power = 0x78;
- radio_parms->tx_offset_db = 0x0;
-
- memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal,
- sizeof(tx_rate_limits_normal));
- memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded,
- sizeof(tx_rate_limits_degraded));
-
- memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b,
- sizeof(tx_channel_limits_11b));
- memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm,
- sizeof(tx_channel_limits_ofdm));
- memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets,
- sizeof(tx_pdv_rate_offsets));
- memcpy(radio_parms->tx_ibias, tx_ibias,
- sizeof(tx_ibias));
-
- radio_parms->rx_fem_insertion_loss = 0x14;
+ radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage);
+ radio_parms->tx_ref_power = r->tx_ref_power;
+ radio_parms->tx_offset_db = r->tx_offset_db;
+
+ memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
+ CONF_NUMBER_OF_RATE_GROUPS);
+
+ memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
+ CONF_NUMBER_OF_CHANNELS_2_4);
+ memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm,
+ CONF_NUMBER_OF_CHANNELS_2_4);
+ memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
+
+ radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
+
+ for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
+ radio_parms->tx_ref_pd_voltage_5[i] =
+ cpu_to_le16(r->tx_ref_pd_voltage_5[i]);
+ memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->tx_rate_limits_normal_5,
+ r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_rate_limits_degraded_5,
+ r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_channel_limits_ofdm_5,
+ r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
+ memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->rx_fem_insertion_loss_5,
+ r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
@@ -311,8 +323,8 @@ int wl1271_hw_init(struct wl1271 *wl)
/* RX config */
ret = wl1271_init_rx_config(wl,
- RX_CFG_PROMISCUOUS | RX_CFG_TSF,
- RX_FILTER_OPTION_DEF);
+ RX_CFG_PROMISCUOUS | RX_CFG_TSF,
+ RX_FILTER_OPTION_DEF);
/* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
RX_FILTER_OPTION_FILTER_ALL); */
if (ret < 0)
@@ -323,6 +335,11 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ /* Initialize connection monitoring thresholds */
+ ret = wl1271_acx_conn_monit_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Beacon filtering */
ret = wl1271_init_beacon_filter(wl);
if (ret < 0)
@@ -369,7 +386,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Configure TX rate classes */
- ret = wl1271_acx_rate_policies(wl);
+ ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL);
if (ret < 0)
goto out_free_memmap;
@@ -388,10 +405,16 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ /* Configure smart reflex */
+ ret = wl1271_acx_smart_reflex(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
return 0;
out_free_memmap:
kfree(wl->target_mem_map);
+ wl->target_mem_map = NULL;
return ret;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h
index bd8ff0fa227..6e21ceee76a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.h
+++ b/drivers/net/wireless/wl12xx/wl1271_init.h
@@ -48,19 +48,6 @@ struct wl1271_general_parms {
u8 settings;
} __attribute__ ((packed));
-enum ref_clk_enum {
- REF_CLK_19_2_E,
- REF_CLK_26_E,
- REF_CLK_38_4_E,
- REF_CLK_52_E
-};
-
-#define RSSI_AND_PROCESS_COMPENSATION_SIZE 15
-#define NUMBER_OF_SUB_BANDS_5 7
-#define NUMBER_OF_RATE_GROUPS 6
-#define NUMBER_OF_CHANNELS_2_4 14
-#define NUMBER_OF_CHANNELS_5 35
-
struct wl1271_radio_parms {
u8 id;
u8 padding[3];
@@ -69,45 +56,45 @@ struct wl1271_radio_parms {
/* 2.4GHz */
u8 rx_trace_loss;
u8 tx_trace_loss;
- s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE];
+ s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* 5GHz */
- u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5];
- u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5];
- s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE];
+ u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* Dynamic radio parameters */
/* 2.4GHz */
- s16 tx_ref_pd_voltage;
+ __le16 tx_ref_pd_voltage;
s8 tx_ref_power;
s8 tx_offset_db;
- s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4];
- s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4];
- s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS];
+ s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
- u8 tx_ibias[NUMBER_OF_RATE_GROUPS];
+ u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 padding2;
/* 5GHz */
- s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5];
- s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5];
- s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5];
+ __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5];
- s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS];
+ s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
+ s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
/* FIXME: this is inconsistent with the types for 2.4GHz */
- s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS];
- s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5];
+ s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 padding3[2];
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 27298b19d5b..86132bb0078 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -30,7 +30,9 @@
#include <linux/spi/spi.h>
#include <linux/crc32.h>
#include <linux/etherdevice.h>
+#include <linux/vmalloc.h>
#include <linux/spi/wl12xx.h>
+#include <linux/inetdevice.h>
#include "wl1271.h"
#include "wl12xx_80211.h"
@@ -45,6 +47,308 @@
#include "wl1271_cmd.h"
#include "wl1271_boot.h"
+static struct conf_drv_settings default_conf = {
+ .sg = {
+ .per_threshold = 7500,
+ .max_scan_compensation_time = 120000,
+ .nfs_sample_interval = 400,
+ .load_ratio = 50,
+ .auto_ps_mode = 0,
+ .probe_req_compensation = 170,
+ .scan_window_compensation = 50,
+ .antenna_config = 0,
+ .beacon_miss_threshold = 60,
+ .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
+ .rate_adaptation_snr = 0
+ },
+ .rx = {
+ .rx_msdu_life_time = 512000,
+ .packet_detection_threshold = 0,
+ .ps_poll_timeout = 15,
+ .upsd_timeout = 15,
+ .rts_threshold = 2347,
+ .rx_cca_threshold = 0xFFEF,
+ .irq_blk_threshold = 0,
+ .irq_pkt_threshold = USHORT_MAX,
+ .irq_timeout = 5,
+ .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
+ },
+ .tx = {
+ .tx_energy_detection = 0,
+ .rc_conf = {
+ .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
+ .short_retry_limit = 10,
+ .long_retry_limit = 10,
+ .aflags = 0
+ },
+ .ac_conf_count = 4,
+ .ac_conf = {
+ [0] = {
+ .ac = CONF_TX_AC_BE,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = 3,
+ .tx_op_limit = 0,
+ },
+ [1] = {
+ .ac = CONF_TX_AC_BK,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = 7,
+ .tx_op_limit = 0,
+ },
+ [2] = {
+ .ac = CONF_TX_AC_VI,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = CONF_TX_AIFS_PIFS,
+ .tx_op_limit = 3008,
+ },
+ [3] = {
+ .ac = CONF_TX_AC_VO,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = CONF_TX_AIFS_PIFS,
+ .tx_op_limit = 1504,
+ },
+ },
+ .tid_conf_count = 7,
+ .tid_conf = {
+ [0] = {
+ .queue_id = 0,
+ .channel_type = CONF_CHANNEL_TYPE_DCF,
+ .tsid = CONF_TX_AC_BE,
+ .ps_scheme = CONF_PS_SCHEME_LEGACY,
+ .ack_policy = CONF_ACK_POLICY_LEGACY,
+ .apsd_conf = {0, 0},
+ },
+ [1] = {
+ .queue_id = 1,
+ .channel_type = CONF_CHANNEL_TYPE_DCF,
+ .tsid = CONF_TX_AC_BE,
+ .ps_scheme = CONF_PS_SCHEME_LEGACY,
+ .ack_policy = CONF_ACK_POLICY_LEGACY,
+ .apsd_conf = {0, 0},
+ },
+ [2] = {
+ .queue_id = 2,
+ .channel_type = CONF_CHANNEL_TYPE_DCF,
+ .tsid = CONF_TX_AC_BE,
+ .ps_scheme = CONF_PS_SCHEME_LEGACY,
+ .ack_policy = CONF_ACK_POLICY_LEGACY,
+ .apsd_conf = {0, 0},
+ },
+ [3] = {
+ .queue_id = 3,
+ .channel_type = CONF_CHANNEL_TYPE_DCF,
+ .tsid = CONF_TX_AC_BE,
+ .ps_scheme = CONF_PS_SCHEME_LEGACY,
+ .ack_policy = CONF_ACK_POLICY_LEGACY,
+ .apsd_conf = {0, 0},
+ },
+ [4] = {
+ .queue_id = 4,
+ .channel_type = CONF_CHANNEL_TYPE_DCF,
+ .tsid = CONF_TX_AC_BE,
+ .ps_scheme = CONF_PS_SCHEME_LEGACY,
+ .ack_policy = CONF_ACK_POLICY_LEGACY,
+ .apsd_conf = {0, 0},
+ },
+ [5] = {
+ .queue_id = 5,
+ .channel_type = CONF_CHANNEL_TYPE_DCF,
+ .tsid = CONF_TX_AC_BE,
+ .ps_scheme = CONF_PS_SCHEME_LEGACY,
+ .ack_policy = CONF_ACK_POLICY_LEGACY,
+ .apsd_conf = {0, 0},
+ },
+ [6] = {
+ .queue_id = 6,
+ .channel_type = CONF_CHANNEL_TYPE_DCF,
+ .tsid = CONF_TX_AC_BE,
+ .ps_scheme = CONF_PS_SCHEME_LEGACY,
+ .ack_policy = CONF_ACK_POLICY_LEGACY,
+ .apsd_conf = {0, 0},
+ }
+ },
+ .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
+ .tx_compl_timeout = 5,
+ .tx_compl_threshold = 5
+ },
+ .conn = {
+ .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
+ .listen_interval = 0,
+ .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
+ .bcn_filt_ie_count = 1,
+ .bcn_filt_ie = {
+ [0] = {
+ .ie = WLAN_EID_CHANNEL_SWITCH,
+ .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
+ }
+ },
+ .synch_fail_thold = 5,
+ .bss_lose_timeout = 100,
+ .beacon_rx_timeout = 10000,
+ .broadcast_timeout = 20000,
+ .rx_broadcast_in_ps = 1,
+ .ps_poll_threshold = 4,
+ .sig_trigger_count = 2,
+ .sig_trigger = {
+ [0] = {
+ .threshold = -75,
+ .pacing = 500,
+ .metric = CONF_TRIG_METRIC_RSSI_BEACON,
+ .type = CONF_TRIG_EVENT_TYPE_EDGE,
+ .direction = CONF_TRIG_EVENT_DIR_LOW,
+ .hysteresis = 2,
+ .index = 0,
+ .enable = 1
+ },
+ [1] = {
+ .threshold = -75,
+ .pacing = 500,
+ .metric = CONF_TRIG_METRIC_RSSI_BEACON,
+ .type = CONF_TRIG_EVENT_TYPE_EDGE,
+ .direction = CONF_TRIG_EVENT_DIR_HIGH,
+ .hysteresis = 2,
+ .index = 1,
+ .enable = 1
+ }
+ },
+ .sig_weights = {
+ .rssi_bcn_avg_weight = 10,
+ .rssi_pkt_avg_weight = 10,
+ .snr_bcn_avg_weight = 10,
+ .snr_pkt_avg_weight = 10
+ },
+ .bet_enable = CONF_BET_MODE_ENABLE,
+ .bet_max_consecutive = 100
+ },
+ .init = {
+ .sr_err_tbl = {
+ [0] = {
+ .len = 7,
+ .upper_limit = 0x03,
+ .values = {
+ 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
+ 0x00 }
+ },
+ [1] = {
+ .len = 7,
+ .upper_limit = 0x03,
+ .values = {
+ 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
+ 0x00 }
+ },
+ [2] = {
+ .len = 7,
+ .upper_limit = 0x03,
+ .values = {
+ 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
+ 0x00 }
+ }
+ },
+ .sr_enable = 1,
+ .genparam = {
+ /*
+ * FIXME: The correct value CONF_REF_CLK_38_4_E
+ * causes the firmware to crash on boot.
+ * The value 5 apparently is an
+ * unnoficial XTAL configuration of the
+ * same frequency, which appears to work.
+ */
+ .ref_clk = 5,
+ .settling_time = 5,
+ .clk_valid_on_wakeup = 0,
+ .dc2dcmode = 0,
+ .single_dual_band = CONF_SINGLE_BAND,
+ .tx_bip_fem_autodetect = 0,
+ .tx_bip_fem_manufacturer = 1,
+ .settings = 1,
+ },
+ .radioparam = {
+ .rx_trace_loss = 10,
+ .tx_trace_loss = 10,
+ .rx_rssi_and_proc_compens = {
+ 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
+ 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
+ 0x00, 0x0a, 0x14 },
+ .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
+ .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
+ .rx_rssi_and_proc_compens_5 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 },
+ .tx_ref_pd_voltage = 0x24e,
+ .tx_ref_power = 0x78,
+ .tx_offset_db = 0x0,
+ .tx_rate_limits_normal = {
+ 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
+ .tx_rate_limits_degraded = {
+ 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
+ .tx_channel_limits_11b = {
+ 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
+ 0x22, 0x50 },
+ .tx_channel_limits_ofdm = {
+ 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
+ 0x20, 0x50 },
+ .tx_pdv_rate_offsets = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .tx_ibias = {
+ 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
+ .rx_fem_insertion_loss = 0x14,
+ .tx_ref_pd_voltage_5 = {
+ 0x0190, 0x01a4, 0x01c3, 0x01d8,
+ 0x020a, 0x021c },
+ .tx_ref_power_5 = {
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
+ .tx_offset_db_5 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .tx_rate_limits_normal_5 = {
+ 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
+ .tx_rate_limits_degraded_5 = {
+ 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
+ .tx_channel_limits_ofdm_5 = {
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50 },
+ .tx_pdv_rate_offsets_5 = {
+ 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
+ .tx_ibias_5 = {
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
+ .rx_fem_insertion_loss_5 = {
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
+ }
+ }
+};
+
+static LIST_HEAD(wl_list);
+
+static void wl1271_conf_init(struct wl1271 *wl)
+{
+
+ /*
+ * This function applies the default configuration to the driver. This
+ * function is invoked upon driver load (spi probe.)
+ *
+ * The configuration is stored in a run-time structure in order to
+ * facilitate for run-time adjustment of any of the parameters. Making
+ * changes to the configuration structure will apply the new values on
+ * the next interface up (wl1271_op_start.)
+ */
+
+ /* apply driver default configuration */
+ memcpy(&wl->conf, &default_conf, sizeof(default_conf));
+
+ if (wl1271_11a_enabled())
+ wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
+}
+
+
static int wl1271_plt_init(struct wl1271 *wl)
{
int ret;
@@ -75,20 +379,14 @@ static void wl1271_power_on(struct wl1271 *wl)
wl->set_power(true);
}
-static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status)
+static void wl1271_fw_status(struct wl1271 *wl,
+ struct wl1271_fw_status *status)
{
u32 total = 0;
int i;
- /*
- * FIXME: Reading the FW status directly from the registers seems to
- * be the right thing to do, but it doesn't work. And in the
- * reference driver, there is a workaround called
- * USE_SDIO_24M_WORKAROUND, which reads the status from memory
- * instead, so we do the same here.
- */
-
- wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status));
+ wl1271_spi_read(wl, FW_STATUS_ADDR, status,
+ sizeof(*status), false);
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@@ -99,25 +397,28 @@ static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status)
/* update number of available TX blocks */
for (i = 0; i < NUM_TX_QUEUES; i++) {
- u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i];
- wl->tx_blocks_freed[i] = status->tx_released_blks[i];
+ u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
+ wl->tx_blocks_freed[i];
+
+ wl->tx_blocks_freed[i] =
+ le32_to_cpu(status->tx_released_blks[i]);
wl->tx_blocks_available += cnt;
total += cnt;
}
/* if more blocks are available now, schedule some tx work */
if (total && !skb_queue_empty(&wl->tx_queue))
- schedule_work(&wl->tx_work);
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
/* update the host-chipset time offset */
- wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
+ wl->time_offset = jiffies_to_usecs(jiffies) -
+ le32_to_cpu(status->fw_localtime);
}
-#define WL1271_IRQ_MAX_LOOPS 10
static void wl1271_irq_work(struct work_struct *work)
{
- u32 intr, ctr = WL1271_IRQ_MAX_LOOPS;
int ret;
+ u32 intr;
struct wl1271 *wl =
container_of(work, struct wl1271, irq_work);
@@ -132,9 +433,10 @@ static void wl1271_irq_work(struct work_struct *work)
if (ret < 0)
goto out;
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ wl1271_fw_status(wl, wl->fw_status);
+ intr = le32_to_cpu(wl->fw_status->intr);
if (!intr) {
wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
goto out_sleep;
@@ -142,46 +444,39 @@ static void wl1271_irq_work(struct work_struct *work)
intr &= WL1271_INTR_MASK;
- do {
- wl1271_fw_status(wl, wl->fw_status);
-
-
- if (intr & (WL1271_ACX_INTR_EVENT_A |
- WL1271_ACX_INTR_EVENT_B)) {
- wl1271_debug(DEBUG_IRQ,
- "WL1271_ACX_INTR_EVENT (0x%x)", intr);
- if (intr & WL1271_ACX_INTR_EVENT_A)
- wl1271_event_handle(wl, 0);
- else
- wl1271_event_handle(wl, 1);
- }
+ if (intr & WL1271_ACX_INTR_EVENT_A) {
+ bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
+ wl1271_event_handle(wl, 0, do_ack);
+ }
- if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
- wl1271_debug(DEBUG_IRQ,
- "WL1271_ACX_INTR_INIT_COMPLETE");
+ if (intr & WL1271_ACX_INTR_EVENT_B) {
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
+ wl1271_event_handle(wl, 1, true);
+ }
- if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
+ if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
+ wl1271_debug(DEBUG_IRQ,
+ "WL1271_ACX_INTR_INIT_COMPLETE");
- if (intr & WL1271_ACX_INTR_DATA) {
- u8 tx_res_cnt = wl->fw_status->tx_results_counter -
- wl->tx_results_count;
+ if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
+ if (intr & WL1271_ACX_INTR_DATA) {
+ u8 tx_res_cnt = wl->fw_status->tx_results_counter -
+ wl->tx_results_count;
- /* check for tx results */
- if (tx_res_cnt)
- wl1271_tx_complete(wl, tx_res_cnt);
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
- wl1271_rx(wl, wl->fw_status);
- }
+ /* check for tx results */
+ if (tx_res_cnt)
+ wl1271_tx_complete(wl, tx_res_cnt);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
- intr &= WL1271_INTR_MASK;
- } while (intr && --ctr);
+ wl1271_rx(wl, wl->fw_status);
+ }
out_sleep:
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_ps_elp_sleep(wl);
@@ -205,7 +500,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl->elp_compl = NULL;
}
- schedule_work(&wl->irq_work);
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_HANDLED;
@@ -231,7 +526,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
}
wl->fw_len = fw->size;
- wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
+ wl->fw = vmalloc(wl->fw_len);
if (!wl->fw) {
wl1271_error("could not allocate memory for the firmware");
@@ -292,7 +587,7 @@ static void wl1271_fw_wakeup(struct wl1271 *wl)
u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP;
- wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+ wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
}
static int wl1271_setup(struct wl1271 *wl)
@@ -314,6 +609,7 @@ static int wl1271_setup(struct wl1271 *wl)
static int wl1271_chip_wakeup(struct wl1271 *wl)
{
+ struct wl1271_partition_set partition;
int ret = 0;
wl1271_power_on(wl);
@@ -323,11 +619,10 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
- wl1271_set_partition(wl,
- 0x00000000,
- 0x00000000,
- REGISTERS_BASE,
- REGISTERS_DOWN_SIZE);
+ memset(&partition, 0, sizeof(partition));
+ partition.reg.start = REGISTERS_BASE;
+ partition.reg.size = REGISTERS_DOWN_SIZE;
+ wl1271_set_partition(wl, &partition);
/* ELP module wake up */
wl1271_fw_wakeup(wl);
@@ -335,7 +630,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
- wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B);
+ wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
@@ -346,7 +641,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
break;
case CHIP_ID_1271_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
@@ -354,56 +649,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
break;
default:
wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
- goto out;
+ goto out_power_off;
}
if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
ret = wl1271_fetch_nvs(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
}
-out:
- return ret;
-}
-
-static void wl1271_filter_work(struct work_struct *work)
-{
- struct wl1271 *wl =
- container_of(work, struct wl1271, filter_work);
- int ret;
-
- mutex_lock(&wl->mutex);
-
- if (wl->state == WL1271_STATE_OFF)
- goto out;
-
- ret = wl1271_ps_elp_wakeup(wl, false);
- if (ret < 0)
- goto out;
-
- /* FIXME: replace the magic numbers with proper definitions */
- ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
- if (ret < 0)
- goto out_sleep;
+ goto out;
-out_sleep:
- wl1271_ps_elp_sleep(wl);
+out_power_off:
+ wl1271_power_off(wl);
out:
- mutex_unlock(&wl->mutex);
+ return ret;
}
int wl1271_plt_start(struct wl1271 *wl)
@@ -429,13 +702,26 @@ int wl1271_plt_start(struct wl1271 *wl)
ret = wl1271_boot(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
ret = wl1271_plt_init(wl);
if (ret < 0)
- goto out;
+ goto out_irq_disable;
+
+ /* Make sure power saving is disabled */
+ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+ if (ret < 0)
+ goto out_irq_disable;
+
+ goto out;
+
+out_irq_disable:
+ wl1271_disable_interrupts(wl);
+
+out_power_off:
+ wl1271_power_off(wl);
out:
mutex_unlock(&wl->mutex);
@@ -462,6 +748,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
wl1271_power_off(wl);
wl->state = WL1271_STATE_OFF;
+ wl->rx_counter = 0;
out:
mutex_unlock(&wl->mutex);
@@ -481,7 +768,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* before that, the tx_work will not be initialized!
*/
- schedule_work(&wl->tx_work);
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
/*
* The workqueue is slow to process the tx_queue and we need stop
@@ -501,6 +788,93 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
+static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
+ void *arg)
+{
+ struct net_device *dev;
+ struct wireless_dev *wdev;
+ struct wiphy *wiphy;
+ struct ieee80211_hw *hw;
+ struct wl1271 *wl;
+ struct wl1271 *wl_temp;
+ struct in_device *idev;
+ struct in_ifaddr *ifa = arg;
+ int ret = 0;
+
+ /* FIXME: this ugly function should probably be implemented in the
+ * mac80211, and here should only be a simple callback handling actual
+ * setting of the filters. Now we need to dig up references to
+ * various structures to gain access to what we need.
+ * Also, because of this, there is no "initial" setting of the filter
+ * in "op_start", because we don't want to dig up struct net_device
+ * there - the filter will be set upon first change of the interface
+ * IP address. */
+
+ dev = ifa->ifa_dev->dev;
+
+ wdev = dev->ieee80211_ptr;
+ if (wdev == NULL)
+ return -ENODEV;
+
+ wiphy = wdev->wiphy;
+ if (wiphy == NULL)
+ return -ENODEV;
+
+ hw = wiphy_priv(wiphy);
+ if (hw == NULL)
+ return -ENODEV;
+
+ /* Check that the interface is one supported by this driver. */
+ wl_temp = hw->priv;
+ list_for_each_entry(wl, &wl_list, list) {
+ if (wl == wl_temp)
+ break;
+ }
+ if (wl == NULL)
+ return -ENODEV;
+
+ /* Get the interface IP address for the device. "ifa" will become
+ NULL if:
+ - there is no IPV4 protocol address configured
+ - there are multiple (virtual) IPV4 addresses configured
+ When "ifa" is NULL, filtering will be disabled.
+ */
+ ifa = NULL;
+ idev = dev->ip_ptr;
+ if (idev)
+ ifa = idev->ifa_list;
+
+ if (ifa && ifa->ifa_next)
+ ifa = NULL;
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+ if (ifa)
+ ret = wl1271_acx_arp_ip_filter(wl, true,
+ (u8 *)&ifa->ifa_address,
+ ACX_IPV4_VERSION);
+ else
+ ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
+ ACX_IPV4_VERSION);
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static struct notifier_block wl1271_dev_notifier = {
+ .notifier_call = wl1271_dev_notify,
+};
+
+
static int wl1271_op_start(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
@@ -523,22 +897,32 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
ret = wl1271_boot(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
ret = wl1271_hw_init(wl);
if (ret < 0)
- goto out;
+ goto out_irq_disable;
wl->state = WL1271_STATE_ON;
wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
-out:
- if (ret < 0)
- wl1271_power_off(wl);
+ goto out;
+
+out_irq_disable:
+ wl1271_disable_interrupts(wl);
+out_power_off:
+ wl1271_power_off(wl);
+
+out:
mutex_unlock(&wl->mutex);
+ if (!ret) {
+ list_add(&wl->list, &wl_list);
+ register_inetaddr_notifier(&wl1271_dev_notifier);
+ }
+
return ret;
}
@@ -551,6 +935,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
+ unregister_inetaddr_notifier(&wl1271_dev_notifier);
+ list_del(&wl->list);
+
mutex_lock(&wl->mutex);
WARN_ON(wl->state != WL1271_STATE_ON);
@@ -570,7 +957,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work);
- cancel_work_sync(&wl->filter_work);
mutex_lock(&wl->mutex);
@@ -581,8 +967,8 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
memset(wl->bssid, 0, ETH_ALEN);
memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
wl->ssid_len = 0;
- wl->listen_int = 1;
wl->bss_type = MAX_BSS_TYPE;
+ wl->band = IEEE80211_BAND_2GHZ;
wl->rx_counter = 0;
wl->elp = false;
@@ -592,8 +978,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_blocks_available = 0;
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
+ wl->tx_security_last_seq = 0;
+ wl->tx_security_seq_16 = 0;
+ wl->tx_security_seq_32 = 0;
wl->time_offset = 0;
wl->session_counter = 0;
+ wl->joined = false;
+
for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0;
@@ -611,6 +1002,12 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
conf->type, conf->mac_addr);
mutex_lock(&wl->mutex);
+ if (wl->vif) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl->vif = conf->vif;
switch (conf->type) {
case NL80211_IFTYPE_STATION:
@@ -634,7 +1031,12 @@ out:
static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
+ struct wl1271 *wl = hw->priv;
+
+ mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
+ wl->vif = NULL;
+ mutex_unlock(&wl->mutex);
}
#if 0
@@ -657,7 +1059,15 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+ if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
+ wl1271_debug(DEBUG_MAC80211, "bssid changed");
+
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+
+ ret = wl1271_cmd_join(wl);
+ if (ret < 0)
+ goto out_sleep;
+ }
ret = wl1271_cmd_build_null_data(wl);
if (ret < 0)
@@ -667,13 +1077,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
if (wl->ssid_len)
memcpy(wl->ssid, conf->ssid, wl->ssid_len);
- if (wl->bss_type != BSS_TYPE_IBSS) {
- /* FIXME: replace the magic numbers with proper definitions */
- ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1);
- if (ret < 0)
- goto out_sleep;
- }
-
if (conf->changed & IEEE80211_IFCC_BEACON) {
beacon = ieee80211_beacon_get(hw, vif);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
@@ -691,12 +1094,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto out_sleep;
-
- /* FIXME: replace the magic numbers with proper definitions */
- ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
-
- if (ret < 0)
- goto out_sleep;
}
out_sleep:
@@ -724,20 +1121,20 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&wl->mutex);
+ wl->band = conf->channel->band;
+
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
if (channel != wl->channel) {
- u8 old_channel = wl->channel;
+ /*
+ * We assume that the stack will configure the right channel
+ * before associating, so we don't need to send a join
+ * command here. We will join the right channel when the
+ * BSSID changes
+ */
wl->channel = channel;
-
- /* FIXME: use beacon interval provided by mac80211 */
- ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
- if (ret < 0) {
- wl->channel = old_channel;
- goto out_sleep;
- }
}
ret = wl1271_cmd_build_null_data(wl);
@@ -782,6 +1179,45 @@ out:
return ret;
}
+struct wl1271_filter_params {
+ bool enabled;
+ int mc_list_length;
+ u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
+};
+
+static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct wl1271_filter_params *fp;
+ int i;
+
+ fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
+ if (!fp) {
+ wl1271_error("Out of memory setting filters.");
+ return 0;
+ }
+
+ /* update multicast filtering parameters */
+ fp->enabled = true;
+ if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
+ mc_count = 0;
+ fp->enabled = false;
+ }
+
+ fp->mc_list_length = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (mc_list->da_addrlen == ETH_ALEN) {
+ memcpy(fp->mc_list[fp->mc_list_length],
+ mc_list->da_addr, ETH_ALEN);
+ fp->mc_list_length++;
+ } else
+ wl1271_warning("Unknown mc address length.");
+ mc_list = mc_list->next;
+ }
+
+ return (u64)(unsigned long)fp;
+}
+
#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_FCSFAIL | \
@@ -791,28 +1227,53 @@ out:
static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
- unsigned int *total,u64 multicast)
+ unsigned int *total, u64 multicast)
{
+ struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
struct wl1271 *wl = hw->priv;
+ int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
+ mutex_lock(&wl->mutex);
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
*total &= WL1271_SUPPORTED_FILTERS;
changed &= WL1271_SUPPORTED_FILTERS;
+ if (*total & FIF_ALLMULTI)
+ ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
+ else if (fp)
+ ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
+ fp->mc_list,
+ fp->mc_list_length);
+ if (ret < 0)
+ goto out_sleep;
+
+ kfree(fp);
+
+ /* FIXME: We still need to set our filters properly */
+
+ /* determine, whether supported filter values have changed */
if (changed == 0)
- return;
+ goto out_sleep;
- /* FIXME: wl->rx_config and wl->rx_filter are not protected */
- wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
+ /* apply configured filters */
+ ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+ if (ret < 0)
+ goto out_sleep;
- /*
- * FIXME: workqueues need to be properly cancelled on stop(), for
- * now let's just disable changing the filter settings. They will
- * be updated any on config().
- */
- /* schedule_work(&wl->filter_work); */
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
}
static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -823,6 +1284,8 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct wl1271 *wl = hw->priv;
const u8 *addr;
int ret;
+ u32 tx_seq_32 = 0;
+ u16 tx_seq_16 = 0;
u8 key_type;
static const u8 bcast_addr[ETH_ALEN] =
@@ -861,11 +1324,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = KEY_TKIP;
key_conf->hw_key_idx = key_conf->keyidx;
+ tx_seq_32 = wl->tx_security_seq_32;
+ tx_seq_16 = wl->tx_security_seq_16;
break;
case ALG_CCMP:
key_type = KEY_AES;
key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ tx_seq_32 = wl->tx_security_seq_32;
+ tx_seq_16 = wl->tx_security_seq_16;
break;
default:
wl1271_error("Unknown key algo 0x%x", key_conf->alg);
@@ -879,7 +1346,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key,
- addr);
+ addr, tx_seq_32, tx_seq_16);
if (ret < 0) {
wl1271_error("Could not add or replace key");
goto out_sleep;
@@ -890,7 +1357,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key,
- addr);
+ addr, 0, 0);
if (ret < 0) {
wl1271_error("Could not remove key");
goto out_sleep;
@@ -921,13 +1388,13 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv;
int ret;
u8 *ssid = NULL;
- size_t ssid_len = 0;
+ size_t len = 0;
wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
if (req->n_ssids) {
ssid = req->ssids[0].ssid;
- ssid_len = req->ssids[0].ssid_len;
+ len = req->ssids[0].ssid_len;
}
mutex_lock(&wl->mutex);
@@ -936,7 +1403,12 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+ if (wl1271_11a_enabled())
+ ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
+ WL1271_SCAN_BAND_DUAL, 3);
+ else
+ ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
+ WL1271_SCAN_BAND_2_4_GHZ, 3);
wl1271_ps_elp_sleep(wl);
@@ -969,6 +1441,22 @@ out:
return ret;
}
+static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
+{
+ struct ieee80211_supported_band *band;
+ u32 enabled_rates = 0;
+ int bit;
+
+ band = wl->hw->wiphy->bands[wl->band];
+ for (bit = 0; bit < band->n_bitrates; bit++) {
+ if (basic_rate_set & 0x1)
+ enabled_rates |= band->bitrates[bit].hw_value;
+ basic_rate_set >>= 1;
+ }
+
+ return enabled_rates;
+}
+
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -990,6 +1478,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
+ /*
+ * with wl1271, we don't need to update the
+ * beacon_int and dtim_period, because the firmware
+ * updates it by itself when the first beacon is
+ * received after a join.
+ */
ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
if (ret < 0)
goto out_sleep;
@@ -1005,8 +1499,14 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out_sleep;
}
+ } else {
+ /* use defaults when not associated */
+ wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+ wl->aid = 0;
}
+
}
+
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
@@ -1036,6 +1536,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ wl->basic_rate_set = wl1271_enabled_rates_get(
+ wl, bss_conf->basic_rates);
+
+ ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
+ if (ret < 0) {
+ wl1271_warning("Set rate policies failed %d", ret);
+ goto out_sleep;
+ }
+ }
+
out_sleep:
wl1271_ps_elp_sleep(wl);
@@ -1047,44 +1558,44 @@ out:
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
{ .bitrate = 10,
- .hw_value = 0x1,
- .hw_value_short = 0x1, },
+ .hw_value = CONF_HW_BIT_RATE_1MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
{ .bitrate = 20,
- .hw_value = 0x2,
- .hw_value_short = 0x2,
+ .hw_value = CONF_HW_BIT_RATE_2MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
.flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 55,
- .hw_value = 0x4,
- .hw_value_short = 0x4,
+ .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
.flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 110,
- .hw_value = 0x20,
- .hw_value_short = 0x20,
+ .hw_value = CONF_HW_BIT_RATE_11MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
.flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 60,
- .hw_value = 0x8,
- .hw_value_short = 0x8, },
+ .hw_value = CONF_HW_BIT_RATE_6MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
{ .bitrate = 90,
- .hw_value = 0x10,
- .hw_value_short = 0x10, },
+ .hw_value = CONF_HW_BIT_RATE_9MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
{ .bitrate = 120,
- .hw_value = 0x40,
- .hw_value_short = 0x40, },
+ .hw_value = CONF_HW_BIT_RATE_12MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
{ .bitrate = 180,
- .hw_value = 0x80,
- .hw_value_short = 0x80, },
+ .hw_value = CONF_HW_BIT_RATE_18MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
{ .bitrate = 240,
- .hw_value = 0x200,
- .hw_value_short = 0x200, },
+ .hw_value = CONF_HW_BIT_RATE_24MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
{ .bitrate = 360,
- .hw_value = 0x400,
- .hw_value_short = 0x400, },
+ .hw_value = CONF_HW_BIT_RATE_36MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
{ .bitrate = 480,
- .hw_value = 0x800,
- .hw_value_short = 0x800, },
+ .hw_value = CONF_HW_BIT_RATE_48MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
{ .bitrate = 540,
- .hw_value = 0x1000,
- .hw_value_short = 0x1000, },
+ .hw_value = CONF_HW_BIT_RATE_54MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
};
/* can't be const, mac80211 writes to this */
@@ -1112,6 +1623,88 @@ static struct ieee80211_supported_band wl1271_band_2ghz = {
.n_bitrates = ARRAY_SIZE(wl1271_rates),
};
+/* 5 GHz data rates for WL1273 */
+static struct ieee80211_rate wl1271_rates_5ghz[] = {
+ { .bitrate = 60,
+ .hw_value = CONF_HW_BIT_RATE_6MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
+ { .bitrate = 90,
+ .hw_value = CONF_HW_BIT_RATE_9MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
+ { .bitrate = 120,
+ .hw_value = CONF_HW_BIT_RATE_12MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
+ { .bitrate = 180,
+ .hw_value = CONF_HW_BIT_RATE_18MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
+ { .bitrate = 240,
+ .hw_value = CONF_HW_BIT_RATE_24MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
+ { .bitrate = 360,
+ .hw_value = CONF_HW_BIT_RATE_36MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
+ { .bitrate = 480,
+ .hw_value = CONF_HW_BIT_RATE_48MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
+ { .bitrate = 540,
+ .hw_value = CONF_HW_BIT_RATE_54MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
+};
+
+/* 5 GHz band channels for WL1273 */
+static struct ieee80211_channel wl1271_channels_5ghz[] = {
+ { .hw_value = 183, .center_freq = 4915},
+ { .hw_value = 184, .center_freq = 4920},
+ { .hw_value = 185, .center_freq = 4925},
+ { .hw_value = 187, .center_freq = 4935},
+ { .hw_value = 188, .center_freq = 4940},
+ { .hw_value = 189, .center_freq = 4945},
+ { .hw_value = 192, .center_freq = 4960},
+ { .hw_value = 196, .center_freq = 4980},
+ { .hw_value = 7, .center_freq = 5035},
+ { .hw_value = 8, .center_freq = 5040},
+ { .hw_value = 9, .center_freq = 5045},
+ { .hw_value = 11, .center_freq = 5055},
+ { .hw_value = 12, .center_freq = 5060},
+ { .hw_value = 16, .center_freq = 5080},
+ { .hw_value = 34, .center_freq = 5170},
+ { .hw_value = 36, .center_freq = 5180},
+ { .hw_value = 38, .center_freq = 5190},
+ { .hw_value = 40, .center_freq = 5200},
+ { .hw_value = 42, .center_freq = 5210},
+ { .hw_value = 44, .center_freq = 5220},
+ { .hw_value = 46, .center_freq = 5230},
+ { .hw_value = 48, .center_freq = 5240},
+ { .hw_value = 52, .center_freq = 5260},
+ { .hw_value = 56, .center_freq = 5280},
+ { .hw_value = 60, .center_freq = 5300},
+ { .hw_value = 64, .center_freq = 5320},
+ { .hw_value = 100, .center_freq = 5500},
+ { .hw_value = 104, .center_freq = 5520},
+ { .hw_value = 108, .center_freq = 5540},
+ { .hw_value = 112, .center_freq = 5560},
+ { .hw_value = 116, .center_freq = 5580},
+ { .hw_value = 120, .center_freq = 5600},
+ { .hw_value = 124, .center_freq = 5620},
+ { .hw_value = 128, .center_freq = 5640},
+ { .hw_value = 132, .center_freq = 5660},
+ { .hw_value = 136, .center_freq = 5680},
+ { .hw_value = 140, .center_freq = 5700},
+ { .hw_value = 149, .center_freq = 5745},
+ { .hw_value = 153, .center_freq = 5765},
+ { .hw_value = 157, .center_freq = 5785},
+ { .hw_value = 161, .center_freq = 5805},
+ { .hw_value = 165, .center_freq = 5825},
+};
+
+
+static struct ieee80211_supported_band wl1271_band_5ghz = {
+ .channels = wl1271_channels_5ghz,
+ .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
+ .bitrates = wl1271_rates_5ghz,
+ .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
+};
+
static const struct ieee80211_ops wl1271_ops = {
.start = wl1271_op_start,
.stop = wl1271_op_stop,
@@ -1119,6 +1712,7 @@ static const struct ieee80211_ops wl1271_ops = {
.remove_interface = wl1271_op_remove_interface,
.config = wl1271_op_config,
/* .config_interface = wl1271_op_config_interface, */
+ .prepare_multicast = wl1271_op_prepare_multicast,
.configure_filter = wl1271_op_configure_filter,
.tx = wl1271_op_tx,
.set_key = wl1271_op_set_key,
@@ -1151,24 +1745,25 @@ static int wl1271_register_hw(struct wl1271 *wl)
static int wl1271_init_ieee80211(struct wl1271 *wl)
{
- /*
- * The tx descriptor buffer and the TKIP space.
- *
- * FIXME: add correct 1271 descriptor size
- */
- wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE;
+ /* The tx descriptor buffer and the TKIP space. */
+ wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
+ sizeof(struct wl1271_tx_hw_descr);
/* unit us */
/* FIXME: find a proper value */
wl->hw->channel_change_time = 10000;
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
+ IEEE80211_HW_NOISE_DBM |
+ IEEE80211_HW_BEACON_FILTER;
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
+ if (wl1271_11a_enabled())
+ wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
+
SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
return 0;
@@ -1213,17 +1808,18 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl = hw->priv;
memset(wl, 0, sizeof(*wl));
+ INIT_LIST_HEAD(&wl->list);
+
wl->hw = hw;
dev_set_drvdata(&spi->dev, wl);
wl->spi = spi;
skb_queue_head_init(&wl->tx_queue);
- INIT_WORK(&wl->filter_work, wl1271_filter_work);
+ INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
wl->channel = WL1271_DEFAULT_CHANNEL;
wl->scanning = false;
wl->default_key = 0;
- wl->listen_int = 1;
wl->rx_counter = 0;
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
@@ -1232,10 +1828,12 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl->psm_requested = false;
wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
+ wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+ wl->band = IEEE80211_BAND_2GHZ;
+ wl->vif = NULL;
+ wl->joined = false;
- /* We use the default power on sleep time until we know which chip
- * we're using */
- for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;
spin_lock_init(&wl->wl_lock);
@@ -1250,13 +1848,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl->state = WL1271_STATE_OFF;
mutex_init(&wl->mutex);
- wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
- if (!wl->rx_descriptor) {
- wl1271_error("could not allocate memory for rx descriptor");
- ret = -ENOMEM;
- goto out_free;
- }
-
/* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */
spi->bits_per_word = 32;
@@ -1298,6 +1889,9 @@ static int __devinit wl1271_probe(struct spi_device *spi)
}
dev_set_drvdata(&wl1271_device.dev, wl);
+ /* Apply default driver configuration. */
+ wl1271_conf_init(wl);
+
ret = wl1271_init_ieee80211(wl);
if (ret)
goto out_platform;
@@ -1319,9 +1913,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
free_irq(wl->irq, wl);
out_free:
- kfree(wl->rx_descriptor);
- wl->rx_descriptor = NULL;
-
ieee80211_free_hw(hw);
return ret;
@@ -1337,14 +1928,11 @@ static int __devexit wl1271_remove(struct spi_device *spi)
platform_device_unregister(&wl1271_device);
free_irq(wl->irq, wl);
kfree(wl->target_mem_map);
- kfree(wl->fw);
+ vfree(wl->fw);
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
- kfree(wl->rx_descriptor);
- wl->rx_descriptor = NULL;
-
kfree(wl->fw_status);
kfree(wl->tx_res_if);
@@ -1391,3 +1979,4 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
+MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index 1dc74b0c773..507cd91d7ee 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -27,25 +27,38 @@
#define WL1271_WAKEUP_TIMEOUT 500
+void wl1271_elp_work(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct wl1271 *wl;
+
+ dwork = container_of(work, struct delayed_work, work);
+ wl = container_of(dwork, struct wl1271, elp_work);
+
+ wl1271_debug(DEBUG_PSM, "elp work");
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->elp || !wl->psm)
+ goto out;
+
+ wl1271_debug(DEBUG_PSM, "chip to elp");
+ wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+ wl->elp = true;
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+#define ELP_ENTRY_DELAY 5
+
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
- /*
- * FIXME: due to a problem in the firmware (causing a firmware
- * crash), ELP entry is prevented below. Remove the "true" to
- * re-enable ELP entry.
- */
- if (true || wl->elp || !wl->psm)
- return;
-
- /*
- * Go to ELP unless there is work already pending - pending work
- * will immediately wakeup the chipset anyway.
- */
- if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) {
- wl1271_debug(DEBUG_PSM, "chip to elp");
- wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
- wl->elp = true;
+ if (wl->psm) {
+ cancel_delayed_work(&wl->elp_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
+ msecs_to_jiffies(ELP_ENTRY_DELAY));
}
}
@@ -73,7 +86,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
wl->elp_compl = &compl;
spin_unlock_irqrestore(&wl->wl_lock, flags);
- wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+ wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
if (!pending) {
ret = wait_for_completion_timeout(
@@ -111,6 +124,17 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
switch (mode) {
case STATION_POWER_SAVE_MODE:
wl1271_debug(DEBUG_PSM, "entering psm");
+
+ /* enable beacon filtering */
+ ret = wl1271_acx_beacon_filter_opt(wl, true);
+ if (ret < 0)
+ return ret;
+
+ /* enable beacon early termination */
+ ret = wl1271_acx_bet_enable(wl, true);
+ if (ret < 0)
+ return ret;
+
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
return ret;
@@ -128,6 +152,16 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
if (ret < 0)
return ret;
+ /* disable beacon early termination */
+ ret = wl1271_acx_bet_enable(wl, false);
+ if (ret < 0)
+ return ret;
+
+ /* disable beacon filtering */
+ ret = wl1271_acx_beacon_filter_opt(wl, false);
+ if (ret < 0)
+ return ret;
+
ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h
index de2bd3c7dc9..779653d0ae8 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.h
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.h
@@ -30,6 +30,6 @@
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode);
void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
-
+void wl1271_elp_work(struct work_struct *work);
#endif /* __WL1271_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h
index f8ed4a4fc69..1f237389d1c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_reg.h
+++ b/drivers/net/wireless/wl12xx/wl1271_reg.h
@@ -34,7 +34,7 @@
#define REGISTERS_WORK_SIZE 0x0000b000
#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC
-#define STATUS_MEM_ADDRESS 0x40400
+#define FW_STATUS_ADDR (0x14FC0 + 0xA000)
/* ELP register commands */
#define ELPCTRL_WAKE_UP 0x1
@@ -213,7 +213,6 @@
==============================================*/
#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0)
-#define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534)
#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538)
/* Device Configuration registers*/
@@ -614,50 +613,6 @@ enum {
MAX_RADIO_BANDS = 0xFF
};
-enum {
- NO_RATE = 0,
- RATE_1MBPS = 0x0A,
- RATE_2MBPS = 0x14,
- RATE_5_5MBPS = 0x37,
- RATE_6MBPS = 0x0B,
- RATE_9MBPS = 0x0F,
- RATE_11MBPS = 0x6E,
- RATE_12MBPS = 0x0A,
- RATE_18MBPS = 0x0E,
- RATE_22MBPS = 0xDC,
- RATE_24MBPS = 0x09,
- RATE_36MBPS = 0x0D,
- RATE_48MBPS = 0x08,
- RATE_54MBPS = 0x0C
-};
-
-enum {
- RATE_INDEX_1MBPS = 0,
- RATE_INDEX_2MBPS = 1,
- RATE_INDEX_5_5MBPS = 2,
- RATE_INDEX_6MBPS = 3,
- RATE_INDEX_9MBPS = 4,
- RATE_INDEX_11MBPS = 5,
- RATE_INDEX_12MBPS = 6,
- RATE_INDEX_18MBPS = 7,
- RATE_INDEX_22MBPS = 8,
- RATE_INDEX_24MBPS = 9,
- RATE_INDEX_36MBPS = 10,
- RATE_INDEX_48MBPS = 11,
- RATE_INDEX_54MBPS = 12,
- RATE_INDEX_MAX = RATE_INDEX_54MBPS,
- MAX_RATE_INDEX,
- INVALID_RATE_INDEX = MAX_RATE_INDEX,
- RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF
-};
-
-enum {
- RATE_MASK_1MBPS = 0x1,
- RATE_MASK_2MBPS = 0x2,
- RATE_MASK_5_5MBPS = 0x4,
- RATE_MASK_11MBPS = 0x20,
-};
-
#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */
#define OFDM_RATE_BIT BIT(6)
#define PBCC_RATE_BIT BIT(7)
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index ad8b6904c5e..37d81ab6acc 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -30,14 +30,15 @@
static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
u32 drv_rx_counter)
{
- return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK;
+ return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
+ RX_MEM_BLOCK_MASK;
}
static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
u32 drv_rx_counter)
{
- return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >>
- RX_BUF_SIZE_SHIFT_DIV;
+ return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
+ RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
}
/* The values of this table must match the wl1271_rates[] array */
@@ -70,6 +71,36 @@ static u8 wl1271_rx_rate_to_idx[] = {
0 /* WL1271_RATE_1 */
};
+/* The values of this table must match the wl1271_rates[] array */
+static u8 wl1271_5_ghz_rx_rate_to_idx[] = {
+ /* MCS rates are used only with 11n */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */
+
+ 7, /* WL1271_RATE_54 */
+ 6, /* WL1271_RATE_48 */
+ 5, /* WL1271_RATE_36 */
+ 4, /* WL1271_RATE_24 */
+
+ /* TI-specific rate */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */
+
+ 3, /* WL1271_RATE_18 */
+ 2, /* WL1271_RATE_12 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_11 */
+ 1, /* WL1271_RATE_9 */
+ 0, /* WL1271_RATE_6 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_5_5 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_2 */
+ WL1271_RX_RATE_UNSUPPORTED /* WL1271_RATE_1 */
+};
+
static void wl1271_rx_status(struct wl1271 *wl,
struct wl1271_rx_descriptor *desc,
struct ieee80211_rx_status *status,
@@ -77,12 +108,21 @@ static void wl1271_rx_status(struct wl1271 *wl,
{
memset(status, 0, sizeof(struct ieee80211_rx_status));
- if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
+ if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
+ WL1271_RX_DESC_BAND_BG) {
status->band = IEEE80211_BAND_2GHZ;
- else
+ status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
+ } else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
+ WL1271_RX_DESC_BAND_A) {
+ status->band = IEEE80211_BAND_5GHZ;
+ status->rate_idx = wl1271_5_ghz_rx_rate_to_idx[desc->rate];
+ } else
wl1271_warning("unsupported band 0x%x",
desc->flags & WL1271_RX_DESC_BAND_MASK);
+ if (unlikely(status->rate_idx == WL1271_RX_RATE_UNSUPPORTED))
+ wl1271_warning("unsupported rate");
+
/*
* FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the
* timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we
@@ -91,12 +131,6 @@ static void wl1271_rx_status(struct wl1271 *wl,
*/
status->signal = desc->rssi;
- /* FIXME: Should this be optimized? */
- status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 /
- (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI);
- status->qual = min(status->qual, 100);
- status->qual = max(status->qual, 0);
-
/*
* FIXME: In wl1251, the SNR should be divided by two. In wl1271 we
* need to divide by two for now, but TI has been discussing about
@@ -109,17 +143,11 @@ static void wl1271_rx_status(struct wl1271 *wl,
if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
- if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL)))
+ if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
status->flag |= RX_FLAG_DECRYPTED;
-
- if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL))
+ if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
status->flag |= RX_FLAG_MMIC_ERROR;
}
-
- status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
-
- if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED)
- wl1271_warning("unsupported rate");
}
static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
@@ -138,7 +166,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
}
buf = skb_put(skb, length);
- wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
+ wl1271_spi_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) buf;
@@ -156,7 +184,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
beacon ? "beacon" : "");
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
- ieee80211_rx(wl->hw, skb);
+ ieee80211_rx_ni(wl->hw, skb);
}
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
@@ -176,15 +204,15 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
break;
}
- wl->rx_mem_pool_addr.addr =
- (mem_block << 8) + wl_mem_map->packet_memory_pool_start;
+ wl->rx_mem_pool_addr.addr = (mem_block << 8) +
+ le32_to_cpu(wl_mem_map->packet_memory_pool_start);
wl->rx_mem_pool_addr.addr_extra =
wl->rx_mem_pool_addr.addr + 4;
/* Choose the block we want to read */
- wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA,
- &wl->rx_mem_pool_addr,
- sizeof(wl->rx_mem_pool_addr), false);
+ wl1271_spi_write(wl, WL1271_SLV_REG_DATA,
+ &wl->rx_mem_pool_addr,
+ sizeof(wl->rx_mem_pool_addr), false);
wl1271_rx_handle_data(wl, buf_size);
@@ -192,9 +220,5 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
}
- wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
-
- /* This is a workaround for some problems in the chip */
- wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1);
-
+ wl1271_spi_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h
index d1ca60e43a2..1ae6d1783ed 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.h
@@ -102,14 +102,14 @@
#define RX_BUF_SIZE_SHIFT_DIV 6
struct wl1271_rx_descriptor {
- u16 length;
+ __le16 length;
u8 status;
u8 flags;
u8 rate;
u8 channel;
s8 rssi;
u8 snr;
- u32 timestamp;
+ __le32 timestamp;
u8 packet_class;
u8 process_id;
u8 pad_len;
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 4a12880c16a..02978a16e73 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -30,17 +30,29 @@
#include "wl12xx_80211.h"
#include "wl1271_spi.h"
-static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr)
+static int wl1271_translate_addr(struct wl1271 *wl, int addr)
{
- return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
-}
-
-static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr)
-{
- return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
+ /*
+ * To translate, first check to which window of addresses the
+ * particular address belongs. Then subtract the starting address
+ * of that window from the address. Then, add offset of the
+ * translated region.
+ *
+ * The translated regions occur next to each other in physical device
+ * memory, so just add the sizes of the preceeding address regions to
+ * get the offset to the new region.
+ *
+ * Currently, only the two first regions are addressed, and the
+ * assumption is that all addresses will fall into either of those
+ * two.
+ */
+ if ((addr >= wl->part.reg.start) &&
+ (addr < wl->part.reg.start + wl->part.reg.size))
+ return addr - wl->part.reg.start + wl->part.mem.size;
+ else
+ return addr - wl->part.mem.start;
}
-
void wl1271_spi_reset(struct wl1271 *wl)
{
u8 *cmd;
@@ -123,133 +135,137 @@ void wl1271_spi_init(struct wl1271 *wl)
/* Set the SPI partitions to access the chip addresses
*
- * There are two VIRTUAL (SPI) partitions (the memory partition and the
- * registers partition), which are mapped to two different areas of the
- * PHYSICAL (hardware) memory. This function also makes other checks to
- * ensure that the partitions are not overlapping. In the diagram below, the
- * memory partition comes before the register partition, but the opposite is
- * also supported.
+ * To simplify driver code, a fixed (virtual) memory map is defined for
+ * register and memory addresses. Because in the chipset, in different stages
+ * of operation, those addresses will move around, an address translation
+ * mechanism is required.
*
- * PHYSICAL address
+ * There are four partitions (three memory and one register partition),
+ * which are mapped to two different areas of the hardware memory.
+ *
+ * Virtual address
* space
*
* | |
- * ...+----+--> mem_start
- * VIRTUAL address ... | |
+ * ...+----+--> mem.start
+ * Physical address ... | |
* space ... | | [PART_0]
* ... | |
- * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size
+ * 00000000 <--+----+... ...+----+--> mem.start + mem.size
* | | ... | |
* |MEM | ... | |
* | | ... | |
- * part_size <--+----+... | | {unused area)
+ * mem.size <--+----+... | | {unused area)
* | | ... | |
* |REG | ... | |
- * part_size | | ... | |
- * + <--+----+... ...+----+--> reg_start
- * reg_size ... | |
- * ... | | [PART_1]
- * ... | |
- * ...+----+--> reg_start + reg_size
+ * mem.size | | ... | |
+ * + <--+----+... ...+----+--> reg.start
+ * reg.size | | ... | |
+ * |MEM2| ... | | [PART_1]
+ * | | ... | |
+ * ...+----+--> reg.start + reg.size
* | |
*
*/
int wl1271_set_partition(struct wl1271 *wl,
- u32 mem_start, u32 mem_size,
- u32 reg_start, u32 reg_size)
+ struct wl1271_partition_set *p)
{
- struct wl1271_partition *partition;
- struct spi_transfer t;
- struct spi_message m;
- size_t len, cmd_len;
- u32 *cmd;
- int addr;
-
- cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition);
- cmd = kzalloc(cmd_len, GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- spi_message_init(&m);
- memset(&t, 0, sizeof(t));
-
- partition = (struct wl1271_partition *) (cmd + 1);
- addr = HW_ACCESS_PART0_SIZE_ADDR;
- len = 2 * sizeof(struct wl1271_partition);
-
- *cmd |= WSPI_CMD_WRITE;
- *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ /* copy partition info */
+ memcpy(&wl->part, p, sizeof(*p));
wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
+ p->mem.start, p->mem.size);
wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
-
- /* Make sure that the two partitions together don't exceed the
- * address range */
- if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
- wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
- " address range. Truncating partition[0].");
- mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
- wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- }
+ p->reg.start, p->reg.size);
+ wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X",
+ p->mem2.start, p->mem2.size);
+ wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X",
+ p->mem3.start, p->mem3.size);
+
+ /* write partition info to the chipset */
+ wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
+ wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
+ wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
+ wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
+ wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
+ wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
+ wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
- if ((mem_start < reg_start) &&
- ((mem_start + mem_size) > reg_start)) {
- /* Guarantee that the memory partition doesn't overlap the
- * registers partition */
- wl1271_debug(DEBUG_SPI, "End of partition[0] is "
- "overlapping partition[1]. Adjusted.");
- mem_size = reg_start - mem_start;
- wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- } else if ((reg_start < mem_start) &&
- ((reg_start + reg_size) > mem_start)) {
- /* Guarantee that the register partition doesn't overlap the
- * memory partition */
- wl1271_debug(DEBUG_SPI, "End of partition[1] is"
- " overlapping partition[0]. Adjusted.");
- reg_size = mem_start - reg_start;
- wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- }
+ return 0;
+}
- partition[0].start = mem_start;
- partition[0].size = mem_size;
- partition[1].start = reg_start;
- partition[1].size = reg_size;
+#define WL1271_BUSY_WORD_TIMEOUT 1000
- wl->physical_mem_addr = mem_start;
- wl->physical_reg_addr = reg_start;
+/* FIXME: Check busy words, removed due to SPI bug */
+#if 0
+static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
+{
+ struct spi_transfer t[1];
+ struct spi_message m;
+ u32 *busy_buf;
+ int num_busy_bytes = 0;
- wl->virtual_mem_addr = 0;
- wl->virtual_reg_addr = mem_size;
+ wl1271_info("spi read BUSY!");
- t.tx_buf = cmd;
- t.len = cmd_len;
- spi_message_add_tail(&t, &m);
+ /*
+ * Look for the non-busy word in the read buffer, and if found,
+ * read in the remaining data into the buffer.
+ */
+ busy_buf = (u32 *)buf;
+ for (; (u32)busy_buf < (u32)buf + len; busy_buf++) {
+ num_busy_bytes += sizeof(u32);
+ if (*busy_buf & 0x1) {
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+ memmove(buf, busy_buf, len - num_busy_bytes);
+ t[0].rx_buf = buf + (len - num_busy_bytes);
+ t[0].len = num_busy_bytes;
+ spi_message_add_tail(&t[0], &m);
+ spi_sync(wl->spi, &m);
+ return;
+ }
+ }
- spi_sync(wl->spi, &m);
+ /*
+ * Read further busy words from SPI until a non-busy word is
+ * encountered, then read the data itself into the buffer.
+ */
+ wl1271_info("spi read BUSY-polling needed!");
- kfree(cmd);
+ num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT;
+ busy_buf = wl->buffer_busyword;
+ while (num_busy_bytes) {
+ num_busy_bytes--;
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+ t[0].rx_buf = busy_buf;
+ t[0].len = sizeof(u32);
+ spi_message_add_tail(&t[0], &m);
+ spi_sync(wl->spi, &m);
+
+ if (*busy_buf & 0x1) {
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+ t[0].rx_buf = buf;
+ t[0].len = len;
+ spi_message_add_tail(&t[0], &m);
+ spi_sync(wl->spi, &m);
+ return;
+ }
+ }
- return 0;
+ /* The SPI bus is unresponsive, the read failed. */
+ memset(buf, 0, len);
+ wl1271_error("SPI read busy-word timeout!\n");
}
+#endif
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed)
+void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[3];
struct spi_message m;
- u8 *busy_buf;
+ u32 *busy_buf;
u32 *cmd;
cmd = &wl->buffer_cmd;
@@ -281,14 +297,16 @@ void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
spi_sync(wl->spi, &m);
- /* FIXME: check busy words */
+ /* FIXME: Check busy words, removed due to SPI bug */
+ /* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1))
+ wl1271_spi_read_busy(wl, buf, len); */
wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed)
+void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[2];
struct spi_message m;
@@ -321,62 +339,77 @@ void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf,
- size_t len)
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
{
int physical;
- physical = wl1271_translate_mem_addr(wl, addr);
+ physical = wl1271_translate_addr(wl, addr);
- wl1271_spi_read(wl, physical, buf, len, false);
+ wl1271_spi_raw_read(wl, physical, buf, len, fixed);
}
-void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf,
- size_t len)
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
{
int physical;
- physical = wl1271_translate_mem_addr(wl, addr);
+ physical = wl1271_translate_addr(wl, addr);
- wl1271_spi_write(wl, physical, buf, len, false);
+ wl1271_spi_raw_write(wl, physical, buf, len, fixed);
}
-void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
+u32 wl1271_spi_read32(struct wl1271 *wl, int addr)
{
- int physical;
-
- physical = wl1271_translate_reg_addr(wl, addr);
+ return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
+}
- wl1271_spi_read(wl, physical, buf, len, fixed);
+void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val)
+{
+ wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
}
-void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{
- int physical;
+ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
+ addr = (addr >> 1) + 0x30000;
+ wl1271_spi_write32(wl, OCP_POR_CTR, addr);
- physical = wl1271_translate_reg_addr(wl, addr);
+ /* write value to OCP_POR_WDATA */
+ wl1271_spi_write32(wl, OCP_DATA_WRITE, val);
- wl1271_spi_write(wl, physical, buf, len, fixed);
+ /* write 1 to OCP_CMD */
+ wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_WRITE);
}
-u32 wl1271_mem_read32(struct wl1271 *wl, int addr)
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
{
- return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr));
-}
+ u32 val;
+ int timeout = OCP_CMD_LOOP;
-void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val)
-{
- wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val);
-}
+ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
+ addr = (addr >> 1) + 0x30000;
+ wl1271_spi_write32(wl, OCP_POR_CTR, addr);
-u32 wl1271_reg_read32(struct wl1271 *wl, int addr)
-{
- return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr));
-}
+ /* write 2 to OCP_CMD */
+ wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_READ);
-void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val)
-{
- wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val);
+ /* poll for data ready */
+ do {
+ val = wl1271_spi_read32(wl, OCP_DATA_READ);
+ timeout--;
+ } while (!(val & OCP_READY_MASK) && timeout);
+
+ if (!timeout) {
+ wl1271_warning("Top register access timed out.");
+ return 0xffff;
+ }
+
+ /* check data status and return if OK */
+ if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
+ return val & 0xffff;
+ else {
+ wl1271_warning("Top register access returned error.");
+ return 0xffff;
+ }
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
index 2c996845864..cb7df1c5631 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.h
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.h
@@ -29,10 +29,14 @@
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
-#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0
-#define HW_ACCESS_PART0_START_ADDR 0x1FFC4
-#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8
-#define HW_ACCESS_PART1_START_ADDR 0x1FFCC
+#define HW_PARTITION_REGISTERS_ADDR 0x1ffc0
+#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR)
+#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4)
+#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8)
+#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12)
+#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16)
+#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20)
+#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
#define HW_ACCESS_REGISTER_SIZE 4
@@ -67,47 +71,56 @@
((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
+#define OCP_CMD_LOOP 32
+
+#define OCP_CMD_WRITE 0x1
+#define OCP_CMD_READ 0x2
+
+#define OCP_READY_MASK BIT(18)
+#define OCP_STATUS_MASK (BIT(16) | BIT(17))
+
+#define OCP_STATUS_NO_RESP 0x00000
+#define OCP_STATUS_OK 0x10000
+#define OCP_STATUS_REQ_FAILED 0x20000
+#define OCP_STATUS_RESP_ERROR 0x30000
/* Raw target IO, address is not translated */
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
+void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
+void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
-/* Memory target IO, address is tranlated to partition 0 */
-void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len);
-void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len);
-u32 wl1271_mem_read32(struct wl1271 *wl, int addr);
-void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val);
+/* Translated target IO */
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+u32 wl1271_spi_read32(struct wl1271 *wl, int addr);
+void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val);
-/* Registers IO */
-void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-u32 wl1271_reg_read32(struct wl1271 *wl, int addr);
-void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val);
+/* Top Register IO */
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
/* INIT and RESET words */
void wl1271_spi_reset(struct wl1271 *wl);
void wl1271_spi_init(struct wl1271 *wl);
int wl1271_set_partition(struct wl1271 *wl,
- u32 part_start, u32 part_size,
- u32 reg_start, u32 reg_size);
+ struct wl1271_partition_set *p);
-static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
+static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
{
- wl1271_spi_read(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ wl1271_spi_raw_read(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
return wl->buffer_32;
}
-static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
+static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
{
wl->buffer_32 = val;
- wl1271_spi_write(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ wl1271_spi_raw_write(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
}
#endif /* __WL1271_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index ff221258b94..00af065c77c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -33,8 +33,7 @@
static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
{
int i;
-
- for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
if (wl->tx_frames[i] == NULL) {
wl->tx_frames[i] = skb;
return i;
@@ -58,8 +57,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
/* approximate the number of blocks required for this packet
in the firmware */
/* FIXME: try to figure out what is done here and make it cleaner */
- total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV;
- excluded = (total_blocks << 2) + (skb->len & 0xff) + 34;
+ total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV;
+ excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34;
total_blocks += (excluded > 252) ? 2 : 1;
total_blocks += TX_HW_BLOCK_SPARE;
@@ -89,15 +88,25 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
{
struct wl1271_tx_hw_descr *desc;
int pad;
+ u16 tx_attr;
desc = (struct wl1271_tx_hw_descr *) skb->data;
+ /* relocate space for security header */
+ if (extra) {
+ void *framestart = skb->data + sizeof(*desc);
+ u16 fc = *(u16 *)(framestart + extra);
+ int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc));
+ memmove(framestart, framestart + extra, hdrlen);
+ }
+
/* configure packet life time */
- desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset;
- desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU;
+ desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) -
+ wl->time_offset);
+ desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
/* configure the tx attributes */
- desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+ tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
/* FIXME: do we know the packet priority? can we identify mgmt
packets, and use max prio for them at least? */
desc->tid = 0;
@@ -106,11 +115,13 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* align the length (and store in terms of words) */
pad = WL1271_TX_ALIGN(skb->len);
- desc->length = pad >> 2;
+ desc->length = cpu_to_le16(pad >> 2);
/* calculate number of padding bytes */
pad = pad - skb->len;
- desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+ tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+
+ desc->tx_attr = cpu_to_le16(tx_attr);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
return 0;
@@ -147,11 +158,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
len = WL1271_TX_ALIGN(skb->len);
/* perform a fixed address block write with the packet */
- wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
+ wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
/* write packet new counter into the write access register */
wl->tx_packets_count++;
- wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+ wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
desc = (struct wl1271_tx_hw_descr *) skb->data;
wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
@@ -254,14 +265,13 @@ out:
static void wl1271_tx_complete_packet(struct wl1271 *wl,
struct wl1271_tx_hw_res_descr *result)
{
-
struct ieee80211_tx_info *info;
struct sk_buff *skb;
- u32 header_len;
+ u16 seq;
int id = result->id;
/* check for id legality */
- if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) {
+ if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) {
wl1271_warning("TX result illegal id: %d", id);
return;
}
@@ -284,22 +294,32 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* info->status.retry_count = result->ack_failures; */
wl->stats.retry_count += result->ack_failures;
- /* get header len */
+ /* update security sequence number */
+ seq = wl->tx_security_seq_16 +
+ (result->lsb_security_sequence_number -
+ wl->tx_security_last_seq);
+ wl->tx_security_last_seq = result->lsb_security_sequence_number;
+
+ if (seq < wl->tx_security_seq_16)
+ wl->tx_security_seq_32++;
+ wl->tx_security_seq_16 = seq;
+
+ /* remove private header from packet */
+ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+
+ /* remove TKIP header space if present */
if (info->control.hw_key &&
- info->control.hw_key->alg == ALG_TKIP)
- header_len = WL1271_TKIP_IV_SPACE +
- sizeof(struct wl1271_tx_hw_descr);
- else
- header_len = sizeof(struct wl1271_tx_hw_descr);
+ info->control.hw_key->alg == ALG_TKIP) {
+ int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen);
+ skb_pull(skb, WL1271_TKIP_IV_SPACE);
+ }
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
" status 0x%x",
result->id, skb, result->ack_failures,
result->rate_class_index, result->status);
- /* remove private header from packet */
- skb_pull(skb, header_len);
-
/* return the packet to the stack */
ieee80211_tx_status(wl->hw, skb);
wl->tx_frames[result->id] = NULL;
@@ -315,8 +335,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
/* read the tx results from the chipset */
- wl1271_spi_mem_read(wl, memmap->tx_result,
- wl->tx_res_if, sizeof(*wl->tx_res_if));
+ wl1271_spi_read(wl, le32_to_cpu(memmap->tx_result),
+ wl->tx_res_if, sizeof(*wl->tx_res_if), false);
/* verify that the result buffer is not getting overrun */
if (count > TX_HW_RESULT_QUEUE_LEN) {
@@ -337,10 +357,10 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
}
/* write host counter to chipset (to ack) */
- wl1271_mem_write32(wl, memmap->tx_result +
+ wl1271_spi_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter),
- wl->tx_res_if->tx_result_fw_counter);
+ le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
}
/* caller must hold wl->mutex */
@@ -364,7 +384,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
ieee80211_tx_status(wl->hw, skb);
}
- for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
if (wl->tx_frames[i] != NULL) {
skb = wl->tx_frames[i];
info = IEEE80211_SKB_CB(skb);
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 4a614067ddb..416396caf0a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -58,7 +58,7 @@
struct wl1271_tx_hw_descr {
/* Length of packet in words, including descriptor+header+data */
- u16 length;
+ __le16 length;
/* Number of extra memory blocks to allocate for this packet in
addition to the number of blocks derived from the packet length */
u8 extra_mem_blocks;
@@ -67,12 +67,12 @@ struct wl1271_tx_hw_descr {
HW!! */
u8 total_mem_blocks;
/* Device time (in us) when the packet arrived to the driver */
- u32 start_time;
+ __le32 start_time;
/* Max delay in TUs until transmission. The last device time the
packet can be transmitted is: startTime+(1024*LifeTime) */
- u16 life_time;
+ __le16 life_time;
/* Bitwise fields - see TX_ATTR... definitions above. */
- u16 tx_attr;
+ __le16 tx_attr;
/* Packet identifier used also in the Tx-Result. */
u8 id;
/* The packet TID value (as User-Priority) */
@@ -100,12 +100,12 @@ struct wl1271_tx_hw_res_descr {
several possible reasons for failure. */
u8 status;
/* Total air access duration including all retrys and overheads.*/
- u16 medium_usage;
+ __le16 medium_usage;
/* The time passed from host xfer to Tx-complete.*/
- u32 fw_handling_time;
+ __le32 fw_handling_time;
/* Total media delay
(from 1st EDCA AIFS counter until TX Complete). */
- u32 medium_delay;
+ __le32 medium_delay;
/* LS-byte of last TKIP seq-num (saved per AC for recovery). */
u8 lsb_security_sequence_number;
/* Retry count - number of transmissions without successful ACK.*/
@@ -118,8 +118,8 @@ struct wl1271_tx_hw_res_descr {
} __attribute__ ((packed));
struct wl1271_tx_hw_res_if {
- u32 tx_result_fw_counter;
- u32 tx_result_host_counter;
+ __le32 tx_result_fw_counter;
+ __le32 tx_result_host_counter;
struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 657c2dbcb7d..055d7bc6f59 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -122,8 +122,8 @@ struct wl12xx_null_data_template {
} __attribute__ ((packed));
struct wl12xx_ps_poll_template {
- u16 fc;
- u16 aid;
+ __le16 fc;
+ __le16 aid;
u8 bssid[ETH_ALEN];
u8 ta[ETH_ALEN];
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 4e79a980013..dfa1b9bc22c 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -755,7 +755,7 @@ static int hw_reset_phy(struct zd_chip *chip)
static int zd1211_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ZD1211_RETRY_MAX, 0x2 },
+ { CR_ZD1211_RETRY_MAX, ZD1211_RETRY_COUNT },
{ CR_RX_THRESHOLD, 0x000c0640 },
};
@@ -767,7 +767,7 @@ static int zd1211_hw_init_hmac(struct zd_chip *chip)
static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ZD1211B_RETRY_MAX, 0x02020202 },
+ { CR_ZD1211B_RETRY_MAX, ZD1211B_RETRY_COUNT },
{ CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f },
{ CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f },
{ CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f },
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 678c139a840..9fd8f3508d6 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -642,13 +642,29 @@ enum {
#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
#define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28)
+/* Value for CR_ZD1211_RETRY_MAX & CR_ZD1211B_RETRY_MAX. Vendor driver uses 2,
+ * we use 0. The first rate is tried (count+2), then all next rates are tried
+ * twice, until 1 Mbits is tried. */
+#define ZD1211_RETRY_COUNT 0
+#define ZD1211B_RETRY_COUNT \
+ (ZD1211_RETRY_COUNT << 0)| \
+ (ZD1211_RETRY_COUNT << 8)| \
+ (ZD1211_RETRY_COUNT << 16)| \
+ (ZD1211_RETRY_COUNT << 24)
+
/* Used to detect PLL lock */
#define UW2453_INTR_REG ((zd_addr_t)0x85c1)
#define CWIN_SIZE 0x007f043f
-#define HWINT_ENABLED 0x004f0000
+#define HWINT_ENABLED \
+ (INT_TX_COMPLETE_EN| \
+ INT_RX_COMPLETE_EN| \
+ INT_RETRY_FAIL_EN| \
+ INT_WAKEUP_EN| \
+ INT_CFG_NEXT_BCN_EN)
+
#define HWINT_DISABLED 0
#define E2P_PWR_INT_GUARD 8
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 6d666359a42..8a243732c51 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -88,6 +88,34 @@ static const struct ieee80211_rate zd_rates[] = {
.flags = 0 },
};
+/*
+ * Zydas retry rates table. Each line is listed in the same order as
+ * in zd_rates[] and contains all the rate used when a packet is sent
+ * starting with a given rates. Let's consider an example :
+ *
+ * "11 Mbits : 4, 3, 2, 1, 0" means :
+ * - packet is sent using 4 different rates
+ * - 1st rate is index 3 (ie 11 Mbits)
+ * - 2nd rate is index 2 (ie 5.5 Mbits)
+ * - 3rd rate is index 1 (ie 2 Mbits)
+ * - 4th rate is index 0 (ie 1 Mbits)
+ */
+
+static const struct tx_retry_rate zd_retry_rates[] = {
+ { /* 1 Mbits */ 1, { 0 }},
+ { /* 2 Mbits */ 2, { 1, 0 }},
+ { /* 5.5 Mbits */ 3, { 2, 1, 0 }},
+ { /* 11 Mbits */ 4, { 3, 2, 1, 0 }},
+ { /* 6 Mbits */ 5, { 4, 3, 2, 1, 0 }},
+ { /* 9 Mbits */ 6, { 5, 4, 3, 2, 1, 0}},
+ { /* 12 Mbits */ 5, { 6, 3, 2, 1, 0 }},
+ { /* 18 Mbits */ 6, { 7, 6, 3, 2, 1, 0 }},
+ { /* 24 Mbits */ 6, { 8, 6, 3, 2, 1, 0 }},
+ { /* 36 Mbits */ 7, { 9, 8, 6, 3, 2, 1, 0 }},
+ { /* 48 Mbits */ 8, {10, 9, 8, 6, 3, 2, 1, 0 }},
+ { /* 54 Mbits */ 9, {11, 10, 9, 8, 6, 3, 2, 1, 0 }}
+};
+
static const struct ieee80211_channel zd_channels[] = {
{ .center_freq = 2412, .hw_value = 1 },
{ .center_freq = 2417, .hw_value = 2 },
@@ -282,7 +310,7 @@ static void zd_op_stop(struct ieee80211_hw *hw)
}
/**
- * tx_status - reports tx status of a packet if required
+ * zd_mac_tx_status - reports tx status of a packet if required
* @hw - a &struct ieee80211_hw pointer
* @skb - a sk-buffer
* @flags: extra flags to set in the TX status info
@@ -295,15 +323,49 @@ static void zd_op_stop(struct ieee80211_hw *hw)
*
* If no status information has been requested, the skb is freed.
*/
-static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- int ackssi, bool success)
+static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
+ int ackssi, struct tx_status *tx_status)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int i;
+ int success = 1, retry = 1;
+ int first_idx;
+ const struct tx_retry_rate *retries;
ieee80211_tx_info_clear_status(info);
- if (success)
+ if (tx_status) {
+ success = !tx_status->failure;
+ retry = tx_status->retry + success;
+ }
+
+ if (success) {
+ /* success */
info->flags |= IEEE80211_TX_STAT_ACK;
+ } else {
+ /* failure */
+ info->flags &= ~IEEE80211_TX_STAT_ACK;
+ }
+
+ first_idx = info->status.rates[0].idx;
+ ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates));
+ retries = &zd_retry_rates[first_idx];
+ ZD_ASSERT(0<=retry && retry<=retries->count);
+
+ info->status.rates[0].idx = retries->rate[0];
+ info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1);
+
+ for (i=1; i<IEEE80211_TX_MAX_RATES-1 && i<retry; i++) {
+ info->status.rates[i].idx = retries->rate[i];
+ info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2);
+ }
+ for (; i<IEEE80211_TX_MAX_RATES && i<retry; i++) {
+ info->status.rates[i].idx = retries->rate[retry-1];
+ info->status.rates[i].count = 1; // (success ? 1:2);
+ }
+ if (i<IEEE80211_TX_MAX_RATES)
+ info->status.rates[i].idx = -1; /* terminate */
+
info->status.ack_signal = ackssi;
ieee80211_tx_status_irqsafe(hw, skb);
}
@@ -316,16 +378,79 @@ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
* transferred. The first frame from the tx queue, will be selected and
* reported as error to the upper layers.
*/
-void zd_mac_tx_failed(struct ieee80211_hw *hw)
+void zd_mac_tx_failed(struct urb *urb)
{
- struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue;
+ struct ieee80211_hw * hw = zd_usb_to_hw(urb->context);
+ struct zd_mac *mac = zd_hw_mac(hw);
+ struct sk_buff_head *q = &mac->ack_wait_queue;
struct sk_buff *skb;
+ struct tx_status *tx_status = (struct tx_status *)urb->transfer_buffer;
+ unsigned long flags;
+ int success = !tx_status->failure;
+ int retry = tx_status->retry + success;
+ int found = 0;
+ int i, position = 0;
- skb = skb_dequeue(q);
- if (skb == NULL)
- return;
+ q = &mac->ack_wait_queue;
+ spin_lock_irqsave(&q->lock, flags);
+
+ skb_queue_walk(q, skb) {
+ struct ieee80211_hdr *tx_hdr;
+ struct ieee80211_tx_info *info;
+ int first_idx, final_idx;
+ const struct tx_retry_rate *retries;
+ u8 final_rate;
+
+ position ++;
+
+ /* if the hardware reports a failure and we had a 802.11 ACK
+ * pending, then we skip the first skb when searching for a
+ * matching frame */
+ if (tx_status->failure && mac->ack_pending &&
+ skb_queue_is_first(q, skb)) {
+ continue;
+ }
+
+ tx_hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* we skip all frames not matching the reported destination */
+ if (unlikely(memcmp(tx_hdr->addr1, tx_status->mac, ETH_ALEN))) {
+ continue;
+ }
+
+ /* we skip all frames not matching the reported final rate */
- tx_status(hw, skb, 0, 0);
+ info = IEEE80211_SKB_CB(skb);
+ first_idx = info->status.rates[0].idx;
+ ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates));
+ retries = &zd_retry_rates[first_idx];
+ if (retry < 0 || retry > retries->count) {
+ continue;
+ }
+
+ ZD_ASSERT(0<=retry && retry<=retries->count);
+ final_idx = retries->rate[retry-1];
+ final_rate = zd_rates[final_idx].hw_value;
+
+ if (final_rate != tx_status->rate) {
+ continue;
+ }
+
+ found = 1;
+ break;
+ }
+
+ if (found) {
+ for (i=1; i<=position; i++) {
+ skb = __skb_dequeue(q);
+ zd_mac_tx_status(hw, skb,
+ mac->ack_pending ? mac->ack_signal : 0,
+ i == position ? tx_status : NULL);
+ mac->ack_pending = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&q->lock, flags);
}
/**
@@ -342,18 +467,27 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hw *hw = info->rate_driver_data[0];
+ struct zd_mac *mac = zd_hw_mac(hw);
+
+ ieee80211_tx_info_clear_status(info);
skb_pull(skb, sizeof(struct zd_ctrlset));
if (unlikely(error ||
(info->flags & IEEE80211_TX_CTL_NO_ACK))) {
- tx_status(hw, skb, 0, !error);
+ /*
+ * FIXME : do we need to fill in anything ?
+ */
+ ieee80211_tx_status_irqsafe(hw, skb);
} else {
- struct sk_buff_head *q =
- &zd_hw_mac(hw)->ack_wait_queue;
+ struct sk_buff_head *q = &mac->ack_wait_queue;
skb_queue_tail(q, skb);
- while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
- zd_mac_tx_failed(hw);
+ while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) {
+ zd_mac_tx_status(hw, skb_dequeue(q),
+ mac->ack_pending ? mac->ack_signal : 0,
+ NULL);
+ mac->ack_pending = 0;
+ }
}
}
@@ -606,27 +740,47 @@ fail:
static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
struct ieee80211_rx_status *stats)
{
+ struct zd_mac *mac = zd_hw_mac(hw);
struct sk_buff *skb;
struct sk_buff_head *q;
unsigned long flags;
+ int found = 0;
+ int i, position = 0;
if (!ieee80211_is_ack(rx_hdr->frame_control))
return 0;
- q = &zd_hw_mac(hw)->ack_wait_queue;
+ q = &mac->ack_wait_queue;
spin_lock_irqsave(&q->lock, flags);
skb_queue_walk(q, skb) {
struct ieee80211_hdr *tx_hdr;
+ position ++;
+
+ if (mac->ack_pending && skb_queue_is_first(q, skb))
+ continue;
+
tx_hdr = (struct ieee80211_hdr *)skb->data;
if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN)))
{
- __skb_unlink(skb, q);
- tx_status(hw, skb, stats->signal, 1);
- goto out;
+ found = 1;
+ break;
}
}
-out:
+
+ if (found) {
+ for (i=1; i<position; i++) {
+ skb = __skb_dequeue(q);
+ zd_mac_tx_status(hw, skb,
+ mac->ack_pending ? mac->ack_signal : 0,
+ NULL);
+ mac->ack_pending = 0;
+ }
+
+ mac->ack_pending = 1;
+ mac->ack_signal = stats->signal;
+ }
+
spin_unlock_irqrestore(&q->lock, flags);
return 1;
}
@@ -709,6 +863,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
skb_reserve(skb, 2);
}
+ /* FIXME : could we avoid this big memcpy ? */
memcpy(skb_put(skb, length), buffer, length);
memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
@@ -999,7 +1154,14 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
hw->queues = 1;
hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
+ /*
+ * Tell mac80211 that we support multi rate retries
+ */
+ hw->max_rates = IEEE80211_TX_MAX_RATES;
+ hw->max_rate_tries = 18; /* 9 rates * 2 retries/rate */
+
skb_queue_head_init(&mac->ack_wait_queue);
+ mac->ack_pending = 0;
zd_chip_init(&mac->chip, hw, intf);
housekeeping_init(mac);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 7c2759118d1..630c298a730 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -140,6 +140,21 @@ struct rx_status {
#define ZD_RX_CRC16_ERROR 0x40
#define ZD_RX_ERROR 0x80
+struct tx_retry_rate {
+ int count; /* number of valid element in rate[] array */
+ int rate[10]; /* retry rates, described by an index in zd_rates[] */
+};
+
+struct tx_status {
+ u8 type; /* must always be 0x01 : USB_INT_TYPE */
+ u8 id; /* must always be 0xa0 : USB_INT_ID_RETRY_FAILED */
+ u8 rate;
+ u8 pad;
+ u8 mac[ETH_ALEN];
+ u8 retry;
+ u8 failure;
+} __attribute__((packed));
+
enum mac_flags {
MAC_FIXED_CHANNEL = 0x01,
};
@@ -150,7 +165,7 @@ struct housekeeping {
#define ZD_MAC_STATS_BUFFER_SIZE 16
-#define ZD_MAC_MAX_ACK_WAITERS 10
+#define ZD_MAC_MAX_ACK_WAITERS 50
struct zd_mac {
struct zd_chip chip;
@@ -184,6 +199,12 @@ struct zd_mac {
/* whether to pass control frames to stack */
unsigned int pass_ctrl:1;
+
+ /* whether we have received a 802.11 ACK that is pending */
+ unsigned int ack_pending:1;
+
+ /* signal strength of the last 802.11 ACK received */
+ int ack_signal;
};
#define ZD_REGDOMAIN_FCC 0x10
@@ -279,7 +300,7 @@ int zd_mac_preinit_hw(struct ieee80211_hw *hw);
int zd_mac_init_hw(struct ieee80211_hw *hw);
int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length);
-void zd_mac_tx_failed(struct ieee80211_hw *hw);
+void zd_mac_tx_failed(struct urb *urb);
void zd_mac_tx_to_dev(struct sk_buff *skb, int error);
#ifdef DEBUG
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 23a6a6d4863..d46f20a57b7 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -419,7 +419,7 @@ static void int_urb_complete(struct urb *urb)
handle_regs_int(urb);
break;
case USB_INT_ID_RETRY_FAILED:
- zd_mac_tx_failed(zd_usb_to_hw(urb->context));
+ zd_mac_tx_failed(urb);
break;
default:
dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
@@ -553,6 +553,8 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
if (length < sizeof(struct rx_length_info)) {
/* It's not a complete packet anyhow. */
+ printk("%s: invalid, small RX packet : %d\n",
+ __func__, length);
return;
}
length_info = (struct rx_length_info *)